Closed grad1e closed 2 years ago
Please, create repo with sample where the issue is reproducible
same
same
Please, create repo with sample where the issue is reproducible
Quick search give me that issues connected with DataBinding https://stackoverflow.com/questions/53184433/what-the-actual-meaning-caused-by-java-lang-runtimeexception-view-must-have-a
ViewBindingPropertyDelegate doesn't support it and I didn't test with DataBinding, but will do that
See #69 Add support of DataBinding
@daryljodanny show code of the layout resource file that crash when use it with VBPD
I was so busy that I literally forgot everything. I’ll help you with this by today night for sure
Got the same error today, also using databinding. It is unnecessary, how the layout file looks like or if you use viewbindingdelegate with or without reflection. Always gives me this error. Here is my layout for research purpose:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
android:id="@+id/headline"
layout="@layout/registration_toolbar"
app:isBold="@{false}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:outsideToolbarTitle="@{@string/fragment_user_data_toolbar_title}" />
<com.google.android.material.tabs.TabLayout
android:id="@+id/tl_user_data"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/headline" />
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/vp_user_data"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tl_user_data" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
<layout>
<data>
<variable
name="outsideToolbarTitle"
type="String" />
<variable
name="isBold"
type="boolean" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/user_standard_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/color_shop_item_background"
android:theme="@style/ThemeOverlay.AppCompat.Light"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/toolbar_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@{outsideToolbarTitle}"
android:textColor="@android:color/black"
android:textSize="@dimen/textHeadlineNormal1"
app:setStyle="@{isBold ? 1 : 0}" />
</com.google.android.material.appbar.MaterialToolbar>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
After looking at the crash file, I found the following source of error: When you access the binding variable in your fragments onDestroyView()
the app will crash with the error: View must have a tag. Here is the error log from me:
java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:502)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Caused by: java.lang.reflect.InvocationTargetException
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)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at by.kirich1409.viewbindingdelegate.internal.BindViewBinding.bind(ViewBindingCache.kt:101)
at by.kirich1409.viewbindingdelegate.ReflectionFragmentViewBindings$viewBinding$3.invoke(FragmentViewBindings.kt:64)
at by.kirich1409.viewbindingdelegate.ReflectionFragmentViewBindings$viewBinding$3.invoke(Unknown Source:2)
at by.kirich1409.viewbindingdelegate.LifecycleViewBindingProperty.getValue(ViewBindingProperty.kt:77)
at by.kirich1409.viewbindingdelegate.FragmentViewBindingProperty.getValue(FragmentViewBindings.kt:42)
at by.kirich1409.viewbindingdelegate.FragmentViewBindingProperty.getValue(FragmentViewBindings.kt:34)
at com.example.app.framework.ui.view.fragment.user.loggedIn.userdata.UserDataHolderFragment.getBinding(UserDataHolderFragment.kt:29)
at com.example.app.framework.ui.view.fragment.user.loggedIn.userdata.UserDataHolderFragment.onDestroyView(UserDataHolderFragment.kt:72)
at androidx.fragment.app.Fragment.performDestroyView(Fragment.java:3200)
at androidx.fragment.app.FragmentStateManager.destroyFragmentView(FragmentStateManager.java:742)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:346)
at androidx.fragment.app.SpecialEffectsController$FragmentStateManagerOperation.complete(SpecialEffectsController.java:742)
at androidx.fragment.app.SpecialEffectsController$Operation.completeSpecialEffect(SpecialEffectsController.java:669)
at androidx.fragment.app.DefaultSpecialEffectsController$SpecialEffectsInfo.completeSpecialEffect(DefaultSpecialEffectsController.java:774)
at androidx.fragment.app.DefaultSpecialEffectsController.startAnimations(DefaultSpecialEffectsController.java:147)
at androidx.fragment.app.DefaultSpecialEffectsController.executeOperations(DefaultSpecialEffectsController.java:120)
at androidx.fragment.app.SpecialEffectsController.executePendingOperations(SpecialEffectsController.java:294)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2202)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2106)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:2002)
at androidx.fragment.app.FragmentManager$5.run(FragmentManager.java:524)
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)
Caused by: java.lang.RuntimeException: view must have a tag
at com.example.app.DataBinderMapperImpl.getDataBinder(DataBinderMapperImpl.java:991)
at androidx.databinding.MergedDataBinderMapper.getDataBinder(MergedDataBinderMapper.java:74)
at androidx.databinding.DataBindingUtil.bind(DataBindingUtil.java:199)
at androidx.databinding.ViewDataBinding.bind(ViewDataBinding.java:695)
at com.example.app.databinding.FragmentUserDataHolderBinding.bind(FragmentUserDataHolderBinding.java:88)
at com.example.app.databinding.FragmentUserDataHolderBinding.bind(FragmentUserDataHolderBinding.java:76)
at java.lang.reflect.Method.invoke(Native Method)
at by.kirich1409.viewbindingdelegate.internal.BindViewBinding.bind(ViewBindingCache.kt:101)
at by.kirich1409.viewbindingdelegate.ReflectionFragmentViewBindings$viewBinding$3.invoke(FragmentViewBindings.kt:64)
at by.kirich1409.viewbindingdelegate.ReflectionFragmentViewBindings$viewBinding$3.invoke(Unknown Source:2)
at by.kirich1409.viewbindingdelegate.LifecycleViewBindingProperty.getValue(ViewBindingProperty.kt:77)
at by.kirich1409.viewbindingdelegate.FragmentViewBindingProperty.getValue(FragmentViewBindings.kt:42)
at by.kirich1409.viewbindingdelegate.FragmentViewBindingProperty.getValue(FragmentViewBindings.kt:34)
at com.example.app.framework.ui.view.fragment.user.loggedIn.userdata.UserDataHolderFragment.getBinding(UserDataHolderFragment.kt:29)
at com.example.app.framework.ui.view.fragment.user.loggedIn.userdata.UserDataHolderFragment.onDestroyView(UserDataHolderFragment.kt:72)
at androidx.fragment.app.Fragment.performDestroyView(Fragment.java:3200)
at androidx.fragment.app.FragmentStateManager.destroyFragmentView(FragmentStateManager.java:742)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:346)
at androidx.fragment.app.SpecialEffectsController$FragmentStateManagerOperation.complete(SpecialEffectsController.java:742)
at androidx.fragment.app.SpecialEffectsController$Operation.completeSpecialEffect(SpecialEffectsController.java:669)
at androidx.fragment.app.DefaultSpecialEffectsController$SpecialEffectsInfo.completeSpecialEffect(DefaultSpecialEffectsController.java:774)
at androidx.fragment.app.DefaultSpecialEffectsController.startAnimations(DefaultSpecialEffectsController.java:147)
at androidx.fragment.app.DefaultSpecialEffectsController.executeOperations(DefaultSpecialEffectsController.java:120)
at androidx.fragment.app.SpecialEffectsController.executePendingOperations(SpecialEffectsController.java:294)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2202)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2106)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:2002)
at androidx.fragment.app.FragmentManager$5.run(FragmentManager.java:524)
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)
D/TransportRuntime.SQLiteEventStore: Storing event with priority=HIGHEST, name=FIREBASE_CRASHLYTICS_REPORT for destination cct
V/FA: Connecting to remote service
D/TransportRuntime.JobInfoScheduler: Scheduling upload for context TransportContext(cct, HIGHEST, MSRodHRwczovL2NyYXNobHl0aWNzcmVwb3J0cy1wYS5nb29nbGVhcGlzLmNvbS92MS9maXJlbG9nL2xlZ2FjeS9iYXRjaGxvZ1xBSXphU3lCcnBTWVQ0RkZMMDlyZUhKaTZIOUZZZGVpU25VVE92Mk0=) with jobId=1585000176 in 1000ms(Backend next call timestamp 1627917474726). Attempt 1
V/FA: Recording user engagement, ms: 17787
I/Process: Sending signal. PID: 3697 SIG: 9
As you can see, the stacktrace points to the fragments#onDestroyView(), in my case it was:
override fun onDestroyView() {
super.onDestroyView()
tabLayoutHelper.onDestroyView()
binding.vpUserData.adapter = null <-- THIS CAUSED THE ERROR
}
After deleting the access to the binding variable in onDestroyView(), the eror was gone. Unfortunately with this case, I am not able to use the viewbindingdelegate anymore, because I have to null my viewPager2.adapter in onDestroyView()
I planed to add callback to the delegate, when view will be destroyed
Hello, is databinding support still being worked on? I tried with 1.5.2 but the crash is still happening. For me it is not related to onDestroyView like @Berki2021 but as the original poster: in onViewCreated when the viewBinding is accessed from a click listener on a button.
1.4.6 works fine, so something changed in 1.4.7 and later.
If you cannot reproduce, please let me know
Hello, is databinding support still being worked on? I tried with 1.5.2 but the crash is still happening. For me it is not related to onDestroyView like @Berki2021 but as the original poster: in onViewCreated when the viewBinding is accessed from a click listener on a button.
1.4.6 works fine, so something changed in 1.4.7 and later.
If you cannot reproduce, please let me know
It will be great if you provide sample where the issue is reproducible
I will try to create a minimal sample.
What I have observed so far is that
private val viewBinding: FragmentLoginScreenBinding by viewBinding( FragmentLoginScreenBinding::bind )
works fine when viewBinding is accessed in onViewCreated() of the fragment.
It crashes when observing a livedata which is called in onViewCreated(). We pass in the viewLifecycleowner, not the fragment lifecycle owner.
viewModel.login().observe( viewLifecycleOwner, { when (it) { is Result.Loading -> { viewBinding.loginButton.showProgress() } is Result.Success -> { }
When viewBinding.loginButton.showProgress() is executed it will crash. This is due to the root ConstraintLayout of the login_fragment not having a tag anymore. (while it does have the correct tag in the xml in the apk)
I noticed the viewBinding became null again in your LifecycleViewBindingProperty, which seems strange:
@MainThread public override fun getValue(thisRef: R, property: KProperty<*>): T { viewBinding?.let { return it }
It seems to be cleared by ClearOnDestroyLifecycleObserver which is triggered when the view lifecycleowner is destroyed. So why is it destroyed?
First I see it being cleared on a previous fragment onDestroyView() is called (which contains a viewBinding access). But then the new login fragment which afaik is stil visible also gets a callback in ClearOnDestroyLifecycleObserver.
Using onViewDestroyed when creating the viewBinding does not make a difference. I wonder why it is needed?
Some more information:
I have two fragments: Home and Login. Home is the first fragment that is shown, it automatically redirects to Login when the user is not logged in.
So the following happens:
A bit later the following happens:
Later when an async operation is finished, I'm accessing the viewBinding again, but since it has become null, the library tries to recreate it, but fails with "view must have a tag" in the google databinding code (AGP 7.0.3)
`private inner class ClearOnDestroy : FragmentManager.FragmentLifecycleCallbacks() {
override fun onFragmentDestroyed(fm: FragmentManager, f: Fragment) {
// Fix for destroying view for case with issue of navigation
postClear()
}
}`
I don't understand why the postClear() is called for the Login Fragment (onDestroyView() is not called by Android on that Login fragment). If it would not call postClear() I believe this issue would be fixed.
Now that I have a clearer understanding I can probably make a small reproducable testcase tomorrow.
I made fix for case when Lifecycle.onDestroy()
wasn't called properly and I think this is the reason
@wbervoets , I've just published 1.5.3 and it must be available in few hours. Please check it and write is the fix working or not
same issue for my app fixed by update to 1.5.3 thx
yes, 1.5.3 works fine. Thanks!
Hi, I'm facing an issue after upgrading to 1.4.7 while clicking a button. Downgrading to 1.4.6 fixed for me. Here's the stack trace and code
Stacktrace
Fragment code
Extension function