androidbroadcast / ViewBindingPropertyDelegate

Make work with Android View Binding simpler
https://proandroiddev.com/make-android-view-binding-great-with-kotlin-b71dd9c87719
Apache License 2.0
1.42k stars 102 forks source link

Random crash when navigating between fragments back and forth. #119

Closed DanManDKo closed 1 year ago

DanManDKo commented 1 year ago

If a user quickly changes screens a crash might occur. I use the navigation component. No reflection version 1.5.9 private val binding by viewBinding(FragmentSearchBinding::bind)

Fatal Exception: java.lang.IllegalStateException: Fragment's view can't be accessed. Fragment isn't added at by.kirich1409.viewbindingdelegate.LifecycleViewBindingProperty.getValue(ViewBindingProperty.kt:87) at by.kirich1409.viewbindingdelegate.FragmentViewBindingProperty.getValue(FragmentViewBindings.kt:63) at by.kirich1409.viewbindingdelegate.FragmentViewBindingProperty.getLifecycleOwner(FragmentViewBindings.kt:52) at by.kirich1409.viewbindingdelegate.FragmentViewBindingProperty.getValue(FragmentViewBindings.kt:52) at SearchFragment.<clinit>(SearchFragment.kt:32) at .SearchFragment.getBinding(SearchFragment.kt:32) at SearchFragment.access$getBinding(SearchFragment.kt:29) at SearchFragment$initSearchView$1.invokeSuspend(SearchFragment.kt:58) at SearchFragment$initSearchView$1.invoke(SearchFragment.kt:13) at SearchFragment$initSearchView$1.invoke(SearchFragment.kt:13) at kotlinx.coroutines.flow.FlowKt__TransformKt$onEach$$inlined$unsafeTransform$1$2.emit(Emitters.kt:223) at kotlinx.coroutines.flow.FlowKt__DelayKt$debounceInternal$1$3$1.invokeSuspend(Delay.kt:233) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:367) at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith$default(DispatchedContinuation.kt:278) at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:18) at kotlinx.coroutines.selects.SelectBuilderImpl$onTimeout$$inlined$Runnable$1.run(Runnable.kt:20) at android.os.Handler.handleCallback(Handler.java:938) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loopOnce(Looper.java:201) at android.os.Looper.loop(Looper.java:288) at android.app.ActivityThread.main(ActivityThread.java:7870) at java.lang.reflect.Method.invoke(Method.java) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)

kirich1409 commented 1 year ago

As I understood your try to get instance of viewbinding in callback os async operation without checking that Fragment's View still exists. Try to do something like this:

// Code inside fragment
{
  // Async callback
  if(fragment.view != null) {
     // do something with viewBinding
  }
}
DanManDKo commented 1 year ago

@kirich1409 It seems like the bug is not the library bug. Decided to replace the delegate in the Fragment where the crash occurs often by BaseBindingFragment. After that, I started receiving the NPE. The new error log allows me to find the true reason of the problem - wrong used lifecycleScope. There is an editText in the fragment and to receive updates I used the coroutine flow and used the wrong scope for it lifecycleScope instead of viewLifecycleOwner.lifecycleScope. After debugging, I realized that the binding was already cleared but but flows callback onEach was trying to call binding.

kirich1409 commented 1 year ago

Hi. A lot of bugs about VBPD connected with wrong Lifecycle or usage outside of View Lifecycle scope in a Fragment