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
顶部语句创建了一个 不可观察的 布尔值,因此无法通过生命周期所有者(在您的情况下是片段)。
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
}
}
我想使用带有数据绑定的 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
顶部语句创建了一个 不可观察的 布尔值,因此无法通过生命周期所有者(在您的情况下是片段)。
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
}
}