Yonibagi
Yonibagi

Reputation: 177

Observe LiveData called when onCreate fragment

In short: when Observe is active it works correctly when I do notify, but when I go back to the previous fragment (I use the navigation component) and again navigate to the current fragment, there is a creation of the fragment, and for some reason the Observe is called.

Why is the Observe not deleted when going back? It should behave according to the fragment's lifecycle. I tried removing on onStop and still the observe called.

More detail: Each of my project fragments is divided into 3 parts: model, viewModel, view In the view section, I first set the viewModel.

class EmergencyFragment : Fragment() {

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

And in onViewCreated I set the Observer object so that any changes made in LiveData I get a change notification here:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
   super.onViewCreated(view, savedInstanceState)
   emergencyFragmentViewModel.isEmergencyEventMediaLDSuccess.observe(viewLifecycleOwner, Observer {
       Log.d("sendEmergencyEvent", "isEmergencyEventMediaLDSuccess observer called")
       }
   })
}

In the ViewModel class, I set the LiveData parameter as follows:

EmergencyFragmentViewModel: ViewModel() {
   var isEmergencyEventMediaLDSuccess: LiveData<Boolean> = MutableLiveData()
       private set
   private val observerEventMedia = Observer<Boolean> { (isEmergencyEventMediaLDSuccess as MutableLiveData).value = it}

And in the init I set an observer:

init {
   EmergencyFragmentModel.isEmergencyEventMediaLDSuccessModel.observeForever(observerEventMedia)
}

And of course removes when needed

override fun onCleared() {
   super.onCleared()
   EmergencyFragmentModel.isEmergencyEventMediaLDSuccessModel.removeObserver(observerEventMedia)
}

The part of the model is defined as follows:

class EmergencyFragmentModel {
   companion object{
       val isEmergencyEventMediaLDSuccessModel: LiveData<Boolean> = MutableLiveData()

And I do request network and when a reply comes back I perform a notify

override fun onResponse(call: Call<Int>, response: Response<Int>) {
   if(response.isSuccessful) {
       (isEmergencyEventLDModelSuccess as MutableLiveData).postValue(true)
       Log.d("succeed", "sendEmergencyEvent success: ${response.body().toString()}")
   }

Can anyone say what I'm missing? Why when there is an active Observe and I go back to the previous fragment (I use the navigation component) and navigate to the current fragment again, the Observe is called? I can understand that when a ViewModel instance is created and it executes setValue for the LiveData parameter, then it is notified. But Why is the observe not removed when I go back? I tried removing the Observe on the onStop and it keeps happening.

override fun onStop() {
        super.onStop()
        emergencyFragmentViewModel.isEmergencyEventMediaLDSuccess.removeObservers(viewLifecycleOwner)
        emergencyFragmentViewModel.isEmergencyEventMediaLDSuccess.removeObserver(observeEmergencyEventLDSuccess)
    }

Upvotes: 3

Views: 2286

Answers (3)

artonbej
artonbej

Reputation: 287

I fixed this by creating an extension in kotlin by checkin the lifecycle state.

fun <T> LiveData<T>.observeOnResumedState(viewLifecycleOwner: LifecycleOwner, observer: Observer<T>) {
    this.observe(viewLifecycleOwner) {
        if (viewLifecycleOwner.lifecycle.currentState == Lifecycle.State.RESUMED) {
            observer.onChanged(it)
        }
    }
}

And here is how i observe

viewModel.result.observeOnResumedState(viewLifecycleOwner) {
    // TODO
}

Upvotes: 0

Allan Lind Jensen
Allan Lind Jensen

Reputation: 48

As I understand your question, you only want to run the observer, when the new value differs from the old one. That can be done by retaining the value in another variable in the viewModel.

    if (newValue == viewModel.retainedValue) return@observe
    viewModel.retainedValue = newValue

Upvotes: 0

Guilherme Lima Pereira
Guilherme Lima Pereira

Reputation: 1434

@Pawel is right. LiveData stores the value and everytime you observe it (in your onViewCreated, in this case), it'll emit the last value stored.

Maybe you want something like SingleLiveEvent, which clean its value after someone reads it.

So when you go back and forth, it won't emit that last value (once it was cleaned).

Upvotes: 1

Related Questions