为什么必须删除作为observeForever添加到LiveData的观察者?

时间:2019-04-29 20:13:28

标签: android android-livedata android-viewmodel android-mvvm

我在Android LiveData documentation上读到过:

  

您可以使用observeForever(Observer)方法在没有关联LifecycleOwner对象的情况下注册观察者。在这种情况下,观察者被视为始终处于活动状态,因此始终会收到有关修改的通知。您可以调用removeObserver(Observer)方法删除这些观察者。

我正在使用ViewModel使用MVVM架构模式构建应用程序,并在ViewModel类中声明LiveDatas。在我的viewModel上,我将observeForever设置为LiveData:

val password by lazy {
    MutableLiveData<String>()
}

init {
    initObservable()
}

private fun initObservable() {
    password.observeForever {
        ...
    }
}

根据我对文档的了解,每次实例化ViewModel(带有先前代码)的视图被破坏时,都应该删除观察者,对吗?但是,一旦视图被销毁(因为ViewModel实例在视图中实例化并且也将被销毁),观察者是否不应该被销毁?

3 个答案:

答案 0 :(得分:0)

  

根据我对文档的了解,我应该删除   每次实例化ViewModel的视图时都会观察者

要实现此目的,您应该在View(活动性,片段)中实例化视图模型,并观察这样的实时数据

val model = ViewModelProviders.of(this).get(MyViewModel::class.java)
        model.getUsers().observe(this, Observer<List<User>>{ users ->
            // update UI
        })

通过传递this可以将实时数据绑定到view's生命周期,因此,当View(活动性,片段)被破坏时,viewmodel和observer也将被破坏。

答案 1 :(得分:0)

“每次实例化ViewModel(带有先前代码)的视图被破坏时,我都应该删除观察者,对吗?”

如果您使用LiveData ViewModel 中观察到observeForever(observer)

  • 您不必担心View的生命周期,因为它与ViewModel的生命不同。 ViewModel应该能够使创建它的View失效。相反,当不需要ViewModel时,框架将调用onCleared(),因此您应该在其中删除观察者。

如果您使用LiveData

视图中观察到observe(lifecyclerowner, observer)
  • 当生命周期所有者被销毁时,观察者将被框架自动删除。


“但是一旦视图被销毁(因为ViewModel实例在视图中实例化并且也将被销毁),观察者是否不应该被销毁?”

这个问题比Android更像是Java问题。

考虑“被摧毁”的含义。 Android框架销毁View或ViewModel时,并不表示该对象已从内存中完全删除。只要有其他引用它们的对象(例如观察者),您的活动和片段就不会被垃圾收集。

如果您调用observe(activity, observer),则Android框架可以跟踪activity实例和observer实例之间的连接,因此可以在需要时杀死observer杀死activity。但是,如果仅调用observeForever(observer),则Android Framework根本无法告诉该观察者属于哪个对象。

答案 2 :(得分:0)

ViewModel 中实现 Sanlok Lee 的答案,它看起来像这样:

val password by lazy {
    MutableLiveData<String>()
}

private val passwordObserver = Observer<String> {
    ...
}

init {
    initObservable()
}

private fun initObservable() {
    password.observeForever(passwordObserver)
}

override fun onCleared() {
    password.removeObserver(passwordObserver)
    super.onCleared()
}