首页 > 解决方案 > Kotlin 数据绑定共享视图模型不更新两个视图

问题描述

我正在尝试将共享视图模型用于活动和活动中显示的片段,因为两者都需要由视图模型更新。该片段使用 MutableLiveData 不断更新,但活动不是,我真的不明白为什么。出于可读性原因,我确实删除了与问题无关的 .xml 文件中的布局参数。我的活动代码如下所示:

class MainActivity : AppCompatActivity() {

     private lateinit var _binding : MainActivityBinding
     private val _viewModel : MySharedViewModel by viewModels()

     override fun onCreate(savedInstanceState: Bundle?) {
          super.onCreate(savedInstanceState)
         _binding = DataBindingUtil.setContentView(this, R.layout.main_activity)
         _binding.viewModel = _viewModel
         _binding.lifecycleOwner = this
         ...
     }
}

绑定的生命周期所有者已设置,但 MutableLiveData 似乎并未更新活动。在活动布局文件中如下:

<layout>
<data>
    <variable
        name="viewModel"
        type="com.customApp.viewModels.MySharedViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout>

    <com.google.android.material.appbar.MaterialToolbar>
        <TextView
            android:id="@+id/totalTime"
            android:text="@{viewModel.topBarText}"
            .../>
    </com.google.android.material.appbar.MaterialToolbar>

    <com.google.android.material.bottomnavigation.BottomNavigationView
    .../>

    <androidx.fragment.app.FragmentContainerView
    .../>

</androidx.constraintlayout.widget.ConstraintLayout>

所以我有带有始终显示文本的文本视图的顶部栏,作为标签栏的底部导航视图和包含片段的片段容器视图。

片段代码为:

class FirstFragment : Fragment() {
    private val _viewModel : MySharedViewModel by viewModels()
    private lateinit var _binding : FirstFragmentBinding

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        _binding = DataBindingUtil.inflate(inflater, R.layout.first_fragment, container, false)
        _binding.viewModel = _viewModel
        _binding.lifecycleOwner = viewLifecycleOwner
        return _binding.root
    }
}

同样在这里为绑定设置了生命周期所有者,并且在片段布局中它绑定到了视图模型:

<layout>
    <data>
        <variable
            name="viewModel"
            type="com.customApp.viewModels.MySharedViewModel" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout>
        <TextView
            ...
            android:text="@{viewModel.fragmentText}" />

        <Button
            android:id="@+id/startButton"
            android:onClick="@{() -> viewModel.startIteration()}"
            .../>

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

在我的视图模型中,我只需更新应显示的文本:

class MySharedViewModel : ViewModel() {
    var topBarText : MutableLiveData<String> = MutableLiveData<String>("Hi")
    var fragmentText : MutableLiveData<String> = MutableLiveData<String>("There")

    private val stringsForTop = arrayOf("Hi","How", "You")
    private val stringsForFragment = arrayOf("There","Are", "?")
    private var index = 0

    fun startIteration() {
        kotlin.concurrent.fixedRateTimer(initialDelay = 1L, period = 1000L) {
            viewModelScope.launch(Dispatchers.Main) {
                topBarText.value = stringsForTop[index]
                fragmentText.value = stringsForFragment[index]
                index++
            }
        }
    }
}

现在,在更新片段文本时,顶部栏中的文本不会更新,并且始终只显示“Hi”。我有一种感觉,当片段被初始化并且它的 viewLifecycleOwner 绑定到视图模型时,作为视图模型的生命周期观察者的活动被覆盖了。我是否遗漏了某些东西,或者是否有另一种方法可以在视图模型中向其生命周期所有者注册活动和片段?任何帮助表示赞赏。

标签: androidkotlinmvvmdata-binding

解决方案


如果您by viewmodels<>()在 Fragment 中使用,它将创建ViewModel耦合到Fragment生命周期的新实例。如果您想要与使用ViewModel相同的实例,请尝试以下代码ActivityactivityViewModels<>()Fragment

private val _viewModel : MySharedViewModel by activityViewModels()

推荐阅读