Android 片段 ViewModel 数据绑定未更新 UI 即使设置了 lifecycleOwner

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

我想使用带有数据绑定的 ViewModel 来在单击按钮时禁用复选框,但是 UI 不会更新,除非片段被销毁并重新创建。

类似的问题好像很多,不过最相似的好像都设置binding.lifecycleOwner解决了,我已经搞定了

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
    }
}

我知道我可以通过在 CheckboxDatabindingFragment.kt 中手动获取复选框视图并设置 isEnabled 属性 来轻松执行此功能,但这违背了 DataBinding 的目的。

我需要片段而不是 activity 作为所有者,那么我怎样才能让片段 UI 更新?

问题:

var checkboxEnabled = true

顶部语句创建了一个 不可观察的 布尔值,因此无法通过生命周期所有者(在您的情况下是片段)。

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.

因此,仅使用 binding.lifecycleOwner = viewLifecycleOwner 不足以通过数据绑定发布对布局的更改,而且您还必须使用 lifeCycleOwner 可以观察到的可观察对象,并最终发布对它们的任何更改通过数据绑定到布局。

解决方案:

要解决这个问题,您需要将 checkboxEnabled 更改为可观察的:

选项 1:使用 ObservableBoolean:

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

    val checkboxEnabled = ObservableBoolean(true)

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

选项 2:使用 MutableLiveData:

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

    val checkboxEnabled = MutableLiveData(true)

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