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

Unstable binding in 1.4.7 #72

Closed sandboiii closed 2 years ago

sandboiii commented 3 years ago

Hello, I got some unexpected behavior in version 1.4.7. It's hard to describe what's exactly wrong, basically my binding no longer provides the views I want to access. So, I'll show an example here:

class MyFragment : Fragment() {

    private val viewModel: MyViewModel by activityViewModels()

    private val binding: MyFragmentBinding by viewBinding(createMethod = CreateMethod.INFLATE)

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        binding.myButton.setOnClickListener { viewModel.makeRequest(this::onSuccess, this::onError) }
    }

    private fun onSuccess() {
        // Successful request callback
        ...
    }

    private fun onError() {
        // Unsuccessful request callback
        binding.myTextInputLayout.error = "error happened"
    }
}

In my fragment I have a binding initilized with inflate method. I have a button which makes request and then triggers one of the callbacks. In my onError callback I want to show error in TextInputLayout, however for some reason this code won't do anything. With version 1.4.6 this code works as it supposed to do, but in 1.4.7 there seems to be some kind of a bug and the error text is not displayed. There seems to be something wrong with the binding.

mobinyardim commented 3 years ago

I have the same issue with version 1.4.7, My app crashes in version 1.4.7 but when downgrade to version 1.4.6 every thing is ok. my code:

`class TicketsFragment( viewModelFactory: TicketsViewModel.Factory ) : Fragment(R.layout.fragment_tickets) {

private val binding by viewBinding(FragmentTicketsBinding::bind)

val viewModel by viewModels<TicketsViewModel> {
    TicketsViewModel.provideFactory(
        viewModelFactory
    )
}
val adapter = TicketPagingAdapter(
    TicketPagingAdapter.OnItemClickListener { ticket ->
        findNavController().navigate(
            TicketsFragmentDirections.actionTicketFragmentToTicketThreadsFragment(ticket)
        )
    }
)

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    setupOnClickListeners()
    setupRecyclerView()
}

private fun setupRecyclerView() {

    binding.recyclerView.adapter = adapter.withLoadStateHeaderAndFooter(
        header = InboLoadStateAdapter(adapter),
        footer = InboLoadStateAdapter(adapter)
    )

    binding.swipeToRefresh.setOnRefreshListener {
        adapter.refresh()
        binding.swipeToRefresh.isRefreshing = false
    }

    lifecycleScope.launchWhenCreated {
        adapter.loadStateFlow.collectLatest { loadStates ->
            binding.spinKit.isVisible = loadStates.refresh is LoadState.Loading
        }
    }

    lifecycleScope.launchWhenCreated {
        viewModel.tickets.collectLatest { list ->
            withContext(Dispatchers.Main) {
                adapter.submitData(list)
            }
        }
    }

    lifecycleScope.launchWhenCreated {
        adapter.loadStateFlow.distinctUntilChangedBy { it.refresh }
            .filter { it.refresh is LoadState.NotLoading }
            .collect {
                binding.recyclerView.scrollToPosition(0)
            }
    }

    lifecycleScope.launchWhenCreated {
        adapter.loadStateFlow.map { it.refresh }
            .distinctUntilChanged()
            .collect {
                if (it is LoadState.NotLoading) {
                    viewModel.isListEmpty.value = adapter.itemCount == 0
                }
            }
    }
}

}` and this is log :

2021-08-16 13:14:28.294 10941-10941/ir.inbo.articleapp E/AndroidRuntime: FATAL EXCEPTION: main Process: ir.inbo.articleapp, PID: 10941 java.lang.RuntimeException: view must have a tag at ir.inbo.articleapp.DataBinderMapperImpl.getDataBinder(DataBinderMapperImpl.java:143) at androidx.databinding.MergedDataBinderMapper.getDataBinder(MergedDataBinderMapper.java:79) at androidx.databinding.DataBindingUtil.bind(DataBindingUtil.java:199) at androidx.databinding.ViewDataBinding.bind(ViewDataBinding.java:736) at ir.inbo.articleapp.databinding.FragmentTicketsBinding.bind(FragmentTicketsBinding.java:114) at ir.inbo.articleapp.databinding.FragmentTicketsBinding.bind(FragmentTicketsBinding.java:102) at ir.inbo.articleapp.ui.ticket.TicketsFragment$special$$inlined$viewBindingFragment$default$1.invoke(FragmentViewBindings.kt:133) at ir.inbo.articleapp.ui.ticket.TicketsFragment$special$$inlined$viewBindingFragment$default$1.invoke(FragmentViewBindings.kt:103) 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 ir.inbo.articleapp.ui.ticket.TicketsFragment.getBinding(TicketsFragment.kt:26) at ir.inbo.articleapp.ui.ticket.TicketsFragment.setupRecyclerView$lambda-0(TicketsFragment.kt:55) at ir.inbo.articleapp.ui.ticket.TicketsFragment.$r8$lambda$-NTR2Vt3IWtHG0jh2Yum9Wmyids(Unknown Source:0) at ir.inbo.articleapp.ui.ticket.TicketsFragment$$ExternalSyntheticLambda1.onRefresh(Unknown Source:2) at androidx.swiperefreshlayout.widget.SwipeRefreshLayout$1.onAnimationEnd(SwipeRefreshLayout.java:195) at androidx.swiperefreshlayout.widget.CircleImageView.onAnimationEnd(CircleImageView.java:107) at android.view.ViewGroup.finishAnimatingView(ViewGroup.java:7111) at android.view.View.draw(View.java:22259) at android.view.ViewGroup.drawChild(ViewGroup.java:4516) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4277) at android.view.View.draw(View.java:22353) at android.view.View.updateDisplayListIfDirty(View.java:21226) at android.view.View.draw(View.java:22081) at android.view.ViewGroup.drawChild(ViewGroup.java:4516) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4277) at androidx.constraintlayout.widget.ConstraintLayout.dispatchDraw(ConstraintLayout.java:1975) at android.view.View.updateDisplayListIfDirty(View.java:21217) at android.view.View.draw(View.java:22081) at android.view.ViewGroup.drawChild(ViewGroup.java:4516) at androidx.coordinatorlayout.widget.CoordinatorLayout.drawChild(CoordinatorLayout.java:1277) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4277) at android.view.View.draw(View.java:22353) at android.view.View.updateDisplayListIfDirty(View.java:21226) at android.view.View.draw(View.java:22081) at android.view.ViewGroup.drawChild(ViewGroup.java:4516) at androidx.fragment.app.FragmentContainerView.drawChild(FragmentContainerView.java:268) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4277) at androidx.fragment.app.FragmentContainerView.dispatchDraw(FragmentContainerView.java:256) at android.view.View.updateDisplayListIfDirty(View.java:21217) at android.view.View.draw(View.java:22081) at android.view.ViewGroup.drawChild(ViewGroup.java:4516) at androidx.fragment.app.FragmentContainerView.drawChild(FragmentContainerView.java:268) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4277) at androidx.fragment.app.FragmentContainerView.dispatchDraw(FragmentContainerView.java:256) at android.view.View.updateDisplayListIfDirty(View.java:21217) at android.view.View.draw(View.java:22081) at android.view.ViewGroup.drawChild(ViewGroup.java:4516) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4277) at androidx.constraintlayout.widget.ConstraintLayout.dispatchDraw(ConstraintLayout.java:1975) at android.view.View.updateDisplayListIfDirty(View.java:21217) at android.view.View.draw(View.java:22081) 2021-08-16 13:14:28.297 10941-10941/ir.inbo.articleapp E/AndroidRuntime: at android.view.ViewGroup.drawChild(ViewGroup.java:4516) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4277) at android.view.View.updateDisplayListIfDirty(View.java:21217) at android.view.View.draw(View.java:22081) at android.view.ViewGroup.drawChild(ViewGroup.java:4516) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4277) at android.view.View.updateDisplayListIfDirty(View.java:21217) at android.view.View.draw(View.java:22081) at android.view.ViewGroup.drawChild(ViewGroup.java:4516) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4277) at android.view.View.updateDisplayListIfDirty(View.java:21217) at android.view.View.draw(View.java:22081) at android.view.ViewGroup.drawChild(ViewGroup.java:4516) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4277) at android.view.View.updateDisplayListIfDirty(View.java:21217) at android.view.View.draw(View.java:22081) at android.view.ViewGroup.drawChild(ViewGroup.java:4516) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4277) at android.view.View.draw(View.java:22353) at com.android.internal.policy.DecorView.draw(DecorView.java:806) at android.view.View.updateDisplayListIfDirty(View.java:21226) at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:559) at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:565) at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:642) at android.view.ViewRootImpl.draw(ViewRootImpl.java:4101) at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:3828) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3099) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1952) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:8171) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:972) at android.view.Choreographer.doCallbacks(Choreographer.java:796) at android.view.Choreographer.doFrame(Choreographer.java:731) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:957) at android.os.Handler.handleCallback(Handler.java:938) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:223) at android.app.ActivityThread.main(ActivityThread.java:7656) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)

PsPLoG commented 3 years ago

I'm having the same problem and downgrading to 1.4.6 and still a problem #45

kirich1409 commented 3 years ago

The problem connected with error from DataBinding. Please, show XML layout from the fragment

sandboiii commented 2 years ago

@kirich1409 here is my xml layout:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:id="@+id/my_fragment_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.MyFragment">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        android:scaleX="1.2"
        android:scaleY="1.2"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@drawable/my_frag_img" />

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/my_frag_layout"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:paddingHorizontal="32dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="1.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="1.0">

        <TextView
            android:id="@+id/my_frag_tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_alignParentTop="true"
            android:layout_marginTop="231dp"
            android:fontFamily="sans-serif-medium"
            android:text="My frag text"
            android:textColor="#000"
            android:textSize="20sp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <com.google.android.material.textfield.TextInputLayout
            android:id="@+id/my_text_input_layout"
            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/my_frag_tv">

            <androidx.appcompat.widget.AppCompatEditText
                android:id="@+id/my_fragment_et"
                android:maxLength="4"
                android:gravity="center"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:backgroundTint="@color/my_frag_et_color"
                android:inputType="number" />

        </com.google.android.material.textfield.TextInputLayout>

        <Button
            android:id="@+id/my_button"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            android:background="@color/my_button_color"
            android:padding="22dp"
            android:text="Next"
            android:textColor="@color/white"
            android:textStyle="bold"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/my_text_input_layout" />

        <TextView
            android:id="@+id/my_frag_hint_tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_alignParentTop="true"
            android:layout_marginStart="64dp"
            android:layout_marginEnd="64dp"
            android:layout_marginBottom="16dp"
            android:alpha="0.5"
            android:gravity="center_horizontal|top"
            android:text="Hint text"
            android:textColor="#000"
            android:textSize="14sp"
            android:visibility="gone"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>
kirich1409 commented 2 years ago

@sandboiii , please share the error message

kirich1409 commented 2 years ago

Please, try 1.5.0-beta2

sandboiii commented 2 years ago

@kirich1409 there are no errors, it's just the callback onError not making the layout display the message even though it must do it. I'll check out new version soon

mobinyardim commented 2 years ago

Please, try 1.5.0-beta2

I couldn't find this version :/

sandboiii commented 2 years ago

Today I tried latest beta version and I failed to reproduce this issue even on 1.4.7. I removed implementations of kotlin-reflect and kotlin-stdlib from my build.gradle and updated kotlin plugin to the latest version. And now even version 1.4.7 works correct, I can't reproduce this bug anymore. So, I close this issue.