简体   繁体   中英

Android Fragment ViewModel databinding not updating UI even though lifecycleOwner is set

I want to use a ViewModel with a Databinding to disable a Checkbox when a Button is clicked, but the UI won't update unless the fragment is destroyed and recreated.

There seem to be many similar questions, but the ones that are most similar seem to all be solved by setting binding.lifecycleOwner , which I've already done.

fragment_checkbox_databinding.xml:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".CheckboxDatabindingFragment">
    
    <data>
        <variable
            name="viewModel"
            type=".CheckboxDatabindingFragmentViewModel" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <CheckBox
            android:id="@+id/my_checkbox"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:enabled="@{viewModel.checkboxEnabled}" />

        <Button
            android:id="@+id/my_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="@{() -> viewModel.startClicked()}" />
    
    </LinearLayout>
</layout>

CheckboxDatabindingFragment.kt:

class CheckboxDatabindingFragment() : Fragment() {
    private lateinit var viewModel: CheckboxDatabindingFragmentViewModel

    private var _binding: FragmentCheckboxDatabindingBinding? = null
    private val binding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        viewModel = ViewModelProvider(this).get(CheckboxDatabindingFragmentViewModel::class.java )
        
        _binding = FragmentCheckboxDatabindingBinding.inflate(inflater, container, false)
        binding.lifecycleOwner = viewLifecycleOwner // androidx.fragment.app.FragmentViewLifecycleOwner
        binding.viewModel = viewModel
        
        return binding.root
    }
    ...
}

CheckboxDatabindingFragmentViewModel.kt:

class CheckboxDatabindingFragmentViewModel(application: Application) : AndroidViewModel(application) {
    var checkboxEnabled = true

    fun startClicked() {
        checkboxEnabled = false
    }
}

I know I could easily carry out this functionality by manually getting the checkbox view in CheckboxDatabindingFragment.kt and setting the isEnabled property, but that defeats the purpose of the DataBinding.

I need the fragment, not the activity, to be the owner, so how can I get the fragment UI to update?

Problem:

var checkboxEnabled = true

The top statement creates a non-observable boolean, so no changes on that variable can be observed and submitted to the layout through the life cycle owner (which in your case is the fragment).

But, as per documentation:

Sets the LifecycleOwner that should be used for observing changes of LiveData in this binding. If a LiveData is in one of the binding expressions and no LifecycleOwner is set, the LiveData will not be observed and updates to it will not be propagated to the UI.

So, using binding.lifecycleOwner = viewLifecycleOwner alone is not enough to publish the changes to the layout through databinding, but also you've to use observable objects that can be observed by the lifeCycleOwner and eventually publish any changes on them to the layout via the DataBinding.

Solution:

To solve this you need to change the checkboxEnabled to an observable:

Option 1: use ObservableBoolean :

class CheckboxDatabindingFragmentViewModel(application: Application) : AndroidViewModel(application) {

    val checkboxEnabled = ObservableBoolean(true)

    fun startClicked() {
        checkboxEnabled.set(false)
    }
}

Option 2: use MutableLiveData :

class CheckboxDatabindingFragmentViewModel(application: Application) : AndroidViewModel(application) {

    val checkboxEnabled = MutableLiveData(true)

    fun startClicked() {
        checkboxEnabled.value = false
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM