这是我的实现:
class SampleFragment : Fragment()
{
private val viewModel by sharedViewModel<MyViewModel>()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
FragmentSampleBinding.inflate(inflater, container, false).apply {
myButton.setOnClickListener { viewModel.foo() }
viewModel.statusLiveData.observe(viewLifecycleOwner, Observer {
titleTextView.text = it.status.title
myButton.text = it.status.button_title
})
}.root
}
在极少数情况下,会发生这种崩溃:
java.lang.NullPointerException:
at com.example.fragments.SampleFragment$onCreateView$1$2.onChanged (SampleFragment.kt:2)
at com.example.fragments.SampleFragment$onCreateView$1$2.onChanged (SampleFragment.kt:1)
at androidx.lifecycle.LiveData.considerNotify (LiveData.java:6)
at androidx.lifecycle.LiveData.dispatchingValue (LiveData.java:5)
at androidx.lifecycle.LiveData$ObserverWrapper.activeStateChanged (LiveData.java:10)
at androidx.lifecycle.LiveData$LifecycleBoundObserver.onStateChanged (LiveData.java:3)
at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent (LifecycleRegistry.java:3)
at androidx.lifecycle.LifecycleRegistry.forwardPass (LifecycleRegistry.java:9)
at androidx.lifecycle.LifecycleRegistry.sync (LifecycleRegistry.java:9)
at androidx.lifecycle.LifecycleRegistry.moveToState (LifecycleRegistry.java:5)
at androidx.lifecycle.LifecycleRegistry.handleLifecycleEvent (LifecycleRegistry.java:2)
at androidx.fragment.app.FragmentViewLifecycleOwner.handleLifecycleEvent (FragmentViewLifecycleOwner.java:1)
at androidx.fragment.app.Fragment.performStart (Fragment.java:9)
at androidx.fragment.app.FragmentStateManager.start (FragmentStateManager.java:3)
at androidx.fragment.app.FragmentManager.moveToState (FragmentManager.java:28)
at androidx.fragment.app.FragmentManager.moveToState (FragmentManager.java:69)
at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState (FragmentManager.java:4)
at androidx.fragment.app.FragmentManager.moveToState (FragmentManager.java:75)
at androidx.fragment.app.BackStackRecord.executeOps (BackStackRecord.java:28)
at androidx.fragment.app.FragmentManager.executeOps (FragmentManager.java:6)
at androidx.fragment.app.FragmentManager.executeOpsTogether (FragmentManager.java:14)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute (FragmentManager.java:10)
at androidx.fragment.app.FragmentManager.execPendingActions (FragmentManager.java:4)
at androidx.fragment.app.FragmentManager$4.run (FragmentManager.java:1)
at android.os.Handler.handleCallback (Handler.java:751)
at android.os.Handler.dispatchMessage (Handler.java:95)
at android.os.Looper.loop (Looper.java:154)
at android.app.ActivityThread.main (ActivityThread.java:6823)
at java.lang.reflect.Method.invoke (Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:1563)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1451)
一种想法是,当视图在observe()
订阅结束之前被销毁时会发生这种情况。
我挖掘了片段代码并在 FragmentManager 中找到了这个:
private void destroyFragmentView(@NonNull Fragment fragment) {
fragment.performDestroyView();
mLifecycleCallbacksDispatcher.dispatchOnFragmentViewDestroyed(fragment, false);
fragment.mContainer = null;
fragment.mView = null;
// Set here to ensure that Observers are called after
// the Fragment's view is set to null
fragment.mViewLifecycleOwner = null;
fragment.mViewLifecycleOwnerLiveData.setValue(null);
fragment.mInLayout = false;
}
viewLifecycleOwner
在视图被破坏后,它实际上被破坏了。但是由于这个函数是不可暂停的,所以应该没有办法从主线程交错。
我的假设正确吗?
我进一步发现,viewLifecycleOwner
如果存在退出转换(FragmentManager#moveToState() Lines 1261+),则可以长寿:
// If a fragment has an exit animation (or transition), do not destroy
// its view immediately and set the state after animating
if (mExitAnimationCancellationSignals.get(f) == null) {
destroyFragmentView(f);
} else {
f.setStateAfterAnimating(newState);
}
然而,这也会延迟视图的破坏。
你知道崩溃是如何发生的吗?(我在样品中留下了 Koin 注射液,sharedViewModel
以防这可能是问题的根源。)