简体   繁体   中英

Navigation Component - Problem with Livedata lifecycle

I'm beginning with navigation components and I'm facing some problem with a livedata observer.

For example: I have this livedata, who manage auth response from server.

viewModel.authenticate.observe(this, Observer {
        manageAuthResponse(it)
        })

Everything works fine, and I go to Fragment B. But when I'm in Fragment B, and I try to go back to Fragment A (who contains that livedata), the Observer fires again with the previous result (SUCCESS).

How can I prevent this?

When I go back, I want to refresh this result and prevent livedata observer to be fired.

Wrap your LiveData object in a ConsumableValue like this

class ConsumableValue<T>(private val data: T) {

    private var consumed = false

    fun consume(block: ConsumableValue<T>.(T) -> Unit) {
        if (!consumed) {
            consumed = true
            block(data)
        }
    }
}

then in viewmodel

val authenticate = MutableLiveData<Consumable<AuthenticationObject>>()

and in your fragment

viewModel.authenticate.observe(this, Observer { consumable ->
        consumable.consume {
            manageAuthResponse(it)
        }
    })

Wrap the LiveDate Like this

open class LiveEvent<T> : MediatorLiveData<T>() {

  private val observers = ArraySet<ObserverWrapper<in T>>()

  @MainThread
  override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
    val wrapper = ObserverWrapper(observer)
    observers.add(wrapper)
    super.observe(owner, wrapper)
  }

  @MainThread
  override fun observeForever(observer: Observer<in T>) {
    val wrapper = ObserverWrapper(observer)
    observers.add(wrapper)
    super.observeForever(wrapper)
  }

  @MainThread
  override fun removeObserver(observer: Observer<in T>) {
    if (observers.remove(observer)) {
      super.removeObserver(observer)
      return
    }
    val iterator = observers.iterator()
    while (iterator.hasNext()) {
      val wrapper = iterator.next()
      if (wrapper.observer == observer) {
        iterator.remove()
        super.removeObserver(wrapper)
        break
      }
    }
  }

  @MainThread
  override fun setValue(t: T?) {
    observers.forEach { it.newValue() }
    super.setValue(t)
  }

  private class ObserverWrapper<T>(val observer: Observer<T>) : Observer<T> {

    private var pending = false

    override fun onChanged(t: T?) {
      if (pending) {
        pending = false
        observer.onChanged(t)
      }
    }

    fun newValue() {
      pending = true
    }
  }
}

then in ViewModel

val viewModel = LiveEvent<Resource<String>>()

This solution is work for me

You can check out the code in this github

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