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

IllegalStateException when trying to use view with createMethod = INFLATE #92

Closed arsvechkarev closed 2 years ago

arsvechkarev commented 2 years ago

In 1.4.6, code below that uses view binding delegate with CreateMethod.INFLATE works as expected:

private val mainBinding: ActivityMainBinding by viewBinding(ActivityMainBinding::bind)

// Issue is in this binding
private val innerBinding: ItemToAddBinding by viewBinding(createMethod = CreateMethod.INFLATE)

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    mainBinding.rootLayout.setOnClickListener {
        // Works fine in 1.4.6, but breaks in 1.5.3. Crashes on `innerBinding.itemButton`
        mainBinding.rootLayout.addView(innerBinding.itemButton)
    }
}

In 1.5.3 this code crashes with the following exception:

java.lang.IllegalStateException: Host view isn't ready to create a ViewBinding instance
        at by.kirich1409.viewbindingdelegate.LifecycleViewBindingProperty.getValue(ViewBindingProperty.kt:87)
        at by.kirich1409.viewbindingdelegate.LifecycleViewBindingProperty.getValue(ViewBindingProperty.kt:72)
        at com.arsvechkarev.vbpdtest.MainActivity.getInnerBinding(MainActivity.kt:14)
        at com.arsvechkarev.vbpdtest.MainActivity.onCreate$lambda-0(MainActivity.kt:20)
        at com.arsvechkarev.vbpdtest.MainActivity.$r8$lambda$_81mDixuFKw3tx-DyH6RhN9DAAU(Unknown Source:0)
        at com.arsvechkarev.vbpdtest.MainActivity$$ExternalSyntheticLambda0.onClick(Unknown Source:2)
        at android.view.View.performClick(View.java:7125)
        at android.view.View.performClickInternal(View.java:7102)
        at android.view.View.access$3500(View.java:801)
        at android.view.View$PerformClick.run(View.java:27336)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7356)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)

I suspect that the problem is either in isViewInitialized method in ActivityViewBindingProperty, or in my code above. Any idea on how to fix this?

P.S I created a sample project where you can successfully reproduce this issue

GrishinSergey commented 2 years ago

I have the same case kinda. In my case crash appears after I added logic with cleaning viewBinding delegate:

class MyFragment : Fragment(R.layout.my_fragment) {
    private val bindingDelegate = viewBinding<MyFragment, MyFragmentBinding>(MyFragmentBinding::bind)
    private val binding by bindingDelegate

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)

        viewModel.myLiveData.observe(viewLifecycleOwner) {
            binding.viewToSetData // ... try to interact with view throws IllegalStateException
        }
    }

    override fun onDestroyView() {
        bindingDelegate.clear()
        super.onDestroyView()
    }
}

The crash isn't stable - sometimes it's reproducing, sometimes no. Library version is 1.5.3

kirich1409 commented 2 years ago

In 1.5.6 I added functions that isn't connected to Lifecycle of Activity. You can use them viewBindingLazy() or viewBindingWithLifecycle()

kirich1409 commented 2 years ago

@arsvechkarev did the fix help you?

arsvechkarev commented 2 years ago

Yeah, thanks, upgrading to 1.5.6 solved the problem! Although I'm somewhat confused: was I supposed to use viewBindingWithLifecycle() to fix my issue? Because after upgrading to 1.5.6 my code starts working without me doing anything to it

kirich1409 commented 2 years ago

In your case viewBinding delegate by default connected with lifecycle of Activity. If it normal for you, continue to use it