简体   繁体   中英

LiveData observer fired twice, even with viewLifecycleOwner

I'm struggling with a LiveData observer which is firing twice. In my fragment I'm observing a LiveData as below, using viewLifeCycleOwner as 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)
} 

And this is my view model:

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)
            }
        }
    }

}

When I run the fragment for the first time, everything works fine, however when I go to its DetailFragment and come back, retailLiveData Observer callback is fired twice. According to this article this was a known problem solved with the introduction of viewLifeCycleOwner who should be helpful to remove active observers once fragment's view is destroyed, however it seems not helping in my case.

This happens because view model retains value when you open another fragment, but the fragment's view is destroyed. When you get back to the fragment, view is recreated and you subscribe to retailLiveData , which still holds the previous value and notifies your observer as soon as fragment moves to started state. But you are calling retailViewModel.getRetailById(retail.id) in onViewCreated , so after awhile the value is updated and observer is notified again.

One possible solution is to call getRetailById() from view model's init method, the result will be cached for view model lifetime then.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM