【问题标题】:LiveData observer fired twice, even with viewLifecycleOwnerLiveData 观察者触发了两次,即使使用 viewLifecycleOwner
【发布时间】:2019-12-17 09:53:20
【问题描述】:

我正在与一个触发两次的 LiveData 观察者作斗争。在我的片段中,我观察到LiveData 如下,使用viewLifeCycleOwner 作为LifeCycleOwner

private lateinit var retailViewModel: RetailsViewModel

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        retailViewModel =  ViewModelProviders.of(this).get(RetailsViewModel::class.java)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {

  retailViewModel.retailLiveData.observe(viewLifecycleOwner, Observer {
    // updating UI here, but firing twice!
  }

  retailViewModel.getRetailById(retail.id)
} 

这是我的视图模型:

class RetailsViewModel(override val service: MyFoodyApiService = MyFoodyApiService.service) :
    BaseViewModel(service) {

    var retailLiveData: MutableLiveData<Retail> = MutableLiveData()

    fun getRetailById(id: Int) {
        scope.launch {
            try {
                val response =
                    service.getRetailById(authString, id).await()
                when (response.isSuccessful) {
                    true -> {
                        response.body()?.let { payload ->
                            retailLiveData.postValue(payload.data)
                        } ?: run {
                            errorLiveData.postValue("An error occurred: ${response.message()}")
                        }
                    }
                    false -> errorLiveData.postValue("An error occurred: ${response.message()}")
                }
            } catch (e: Exception) {
                noConnectionLiveData.postValue(true)
            }
        }
    }

}

当我第一次运行片段时,一切正常,但是当我转到它的 DetailFragment 并返回时,retailLiveData Observer 回调被触发了两次。根据this article 的说法,这是通过引入viewLifeCycleOwner 解决的已知问题,一旦fragment 的视图被破坏,viewLifeCycleOwner 应该有助于移除活跃的观察者,但在我的情况下似乎没有帮助。

【问题讨论】:

  • 也许retailViewModel.retailLiveData 更新了两次?也许这是意料之中的。
  • 可能这与presenter/viewmodel逻辑有关,例如从本地缓存中获取一次数据,然后在从远程源更新缓存后再次触发,对吧?
  • @EpicPandaForce 代码更新为调用女巫触发实时数据。我只在观察者之后才称它为 getRetailById。
  • 是的,可以。
  • 也许考虑为您的视图模型操作使用 onAttach() 是一个很好的解决方法。

标签: android kotlin android-lifecycle android-livedata observers


【解决方案1】:

这是因为视图模型在您打开另一个片段时保留值,但片段的视图被破坏。当你回到片段时,视图被重新创建并且你订阅retailLiveData,它仍然保持之前的值,并在片段移动到开始状态时通知你的观察者。但是您在onViewCreated 中调用retailViewModel.getRetailById(retail.id),所以过了一会儿,值会更新并再次通知观察者。

一种可能的解决方案是从视图模型的init 方法调用getRetailById(),然后将结果缓存到视图模型的生命周期。

【讨论】:

  • 谢谢@esentov,这可能是一个解决方案,但是如果我在添加订阅者之前调用 getRetailById() (我正在考虑片段的第一次运行),我是否会收到相同的回调方式?
  • 你只会收到一次回调,因为retailLiveData没有初始值,所以添加时不会通知观察者。只有当值实际设置为实时数据时才会通知。
猜你喜欢
  • 1970-01-01
  • 2018-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多