【问题标题】:Kotlin databinding shared viewmodel not updating both viewsKotlin 数据绑定共享视图模型不更新两个视图
【发布时间】:2021-05-15 04:55:56
【问题描述】:

我正在尝试将共享视图模型用于活动和活动中显示的片段,因为两者都需要由视图模型更新。该片段使用 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 似乎并未更新活动。 在activity布局文件中如下:

<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 绑定到视图模型时,作为视图模型的生命周期观察者的活动被覆盖了。 我是否遗漏了某些东西,或者是否有另一种方法可以在视图模型中向其生命周期所有者注册活动和片段?任何帮助表示赞赏。

【问题讨论】:

    标签: android kotlin mvvm data-binding


    【解决方案1】:

    如果您在 Fragment 中使用 by viewmodels&lt;&gt;(),它将创建与 Fragment 生命周期耦合的 ViewModel 的新实例。如果你想要ViewModel 的相同实例@ 与Activity 使用activityViewModels&lt;&gt;(),请尝试Fragment 中的以下代码

    private val _viewModel : MySharedViewModel by activityViewModels()
    

    【讨论】:

    • 会尝试让您知道它是否有效 :) 感谢您的提示!
    • 就是这样,非常感谢!多年来都不会猜到。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-24
    • 1970-01-01
    相关资源
    最近更新 更多