When I run app and use it no crash. BottomSheetBehavior
works correctly. But if I return to app after a long time pause in background, it crashing with null point exception when try to cast view.parent as View
in order to find View with BottomSheetBehavior
.
Why fragment don't have parent after pause? How to fix it?
I tried to do binding.root.parent as View
and other requireActivity().findViewById(R.id.fragment_sheet_container)
. But the crash with same case continuous.
@AndroidEntryPoint
class ToolboxSheetFragment : Fragment(R.layout.fragment_toolbox_sheet) {
private lateinit var binding: FragmentToolboxSheetBinding
private lateinit var behavior: BottomSheetBehavior<View>
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentToolboxSheetBinding.bind(view)
behavior = BottomSheetBehavior.from(
view.parent as View // null cannot be cast to non-null type android.view.View
)
}
The parent of fragment is main activity with the next layout:
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".view.MainActivity">
// ...
<androidx.fragment.app.FragmentContainerView
android:id="@ id/fragment_sheet_container"
android:name=".view.fragment.ToolboxSheetFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:behavior_hideable="false"
app:behavior_peekHeight="?actionBarSize"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"
tools:layout="@layout/fragment_toolbox_sheet" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
java.lang.RuntimeException: Unable to start activity ComponentInfo{
.view.MainActivity}: java.lang.NullPointerException: null cannot be cast to non-null type android.view.View
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2792)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2870)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1601)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:172)
at android.app.ActivityThread.main(ActivityThread.java:6590)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
Caused by: java.lang.NullPointerException: null cannot be cast to non-null type android.view.View
at .view.fragment.ToolboxSheetFragment.onViewCreated(ToolboxSheetFragment.kt:46)
at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:3128)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:552)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:261)
at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:113)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1424)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2968)
at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:2886)
at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:263)
at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:351)
at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:246)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1335)
at android.app.Activity.performStart(Activity.java:7043)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2755)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2870)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1601)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:172)
at android.app.ActivityThread.main(ActivityThread.java:6590)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
CodePudding user response:
It would be better if I could get full project. But I am suggesting couple of ways here:
Way 1:
How about keeping behavior
inside activity class. instantiate it onCreate()
. And use it from ToolboxSheetFragment
like this.
class MainActivity : BaseActivity() {
var behavior: BottomSheetBehavior? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
behavior = BottomSheetBehavior.from(R.id.sheet_id)
}
}
Then from ToolboxSheetFragment
class ToolboxSheetFragment : Fragment(R.layout.fragment_toolbox_sheet) {
private lateinit var binding: FragmentToolboxSheetBinding
var behavior: BottomSheetBehavior? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentToolboxSheetBinding.bind(view)
behavior = (requireActivity() as MainActivity).behavior
}
Way 2:
Using addOnAttachStateChangeListener
on ToolboxSheetFragment
:
@AndroidEntryPoint
class ToolboxSheetFragment : Fragment(R.layout.fragment_toolbox_sheet) {
private lateinit var binding: FragmentToolboxSheetBinding
private lateinit var behavior: BottomSheetBehavior<View>
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
view.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
override fun onViewAttachedToWindow(v: View?) {
if(v!=null){
binding = FragmentToolboxSheetBinding.bind(v)
behavior = BottomSheetBehavior.from(
v.parent as View
)
}
}
override fun onViewDetachedFromWindow(v: View?) {
view.removeOnAttachStateChangeListener(this)
}
})
}
CodePudding user response:
First inflate the layout in onCreateView()
and you can do all your view related work in onViewCreated()
.
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentToolboxSheetBinding.inflate(layoutInflater)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
behavior = BottomSheetBehavior.from(view)
}