5

I am using MutableLiveData within my application for event based communication. I have single activity two fragments architecture.

With the help of ViewModel, I'm consuming the LiveData events in Fragment-1. But, when I replace this Fragment-1 with Fragment-2 using Menu bar and finally come back to Fragment-1, old values of LiveData are captured again.

How to avoid this problem? Any help/suggestions are highly appreciated! Thank you.

Ningan
  • 151
  • 1
  • 8

5 Answers5

5

You can use Event to wrap LiveData values to handle consuming its values as in the following article: https://medium.com/androiddevelopers/livedata-with-snackbar-navigation-and-other-events-the-singleliveevent-case-ac2622673150

Event class would be like:

open class Event<out T>(private val content: T) {

    var hasBeenHandled = false
        private set // Allow external read but not write

    /**
     * Returns the content and prevents its use again.
     */
    fun getContentIfNotHandled(): T? {
        return if (hasBeenHandled) {
            null
        } else {
            hasBeenHandled = true
            content
        }
    }

    /**
     * Returns the content, even if it's already been handled.
     */
    fun peekContent(): T = content
}

Let us say that your LiveData value is a String then the LiveData of single event would be like:

val navigateToDetails = MutableLiveData<Event<String>>()

Metwalli
  • 1,861
  • 1
  • 18
  • 27
1

Problem with accepted answer is that you can only have one observer. This article describes solution with multiple observers.

0

Wherever you're observing the liveData, in onChanged method remove the observers by calling myLiveDataObject.removeObservers(this); This will remove the observer after first-time data is observed.

Kashish Sharma
  • 749
  • 8
  • 18
0

I faced the same problem and came up with this library to solve it https://github.com/ueen/LiveEvent Hope this helps, enjoy!

ueen
  • 692
  • 3
  • 9
  • 21
0

Simple, clean, reusable:

class Event<T>(val payload: T, var broadcasted: Boolean = false)

class MutableEventLiveData<T>: MutableLiveData<Event<T>>() {
    fun postEvent(value: T) {
        super.postValue(Event(value))
    }
}

typealias EventLiveData<T> = LiveData<Event<T>>

class EventObserver<T>(private val broadcastCallback: (t: T)->Unit): Observer<Event<T>> {

    override fun onChanged(e: Event<T>) {
        if (!e.broadcasted) {
            broadcastCallback(e.payload)
            e.broadcasted = true
        }
    }
}

Sample usage:

class YourViewModel : ViewModel() {
    private val _errorEvent = MutableEventLiveData<String>()
    val errorEvent: EventLiveData<String>
        get() = _errorEvent

    fun fireErrorEvent(errorMessage: String) {
        _errorEvent.postEvent(errorMessage)
    }
    ...
}

class YourActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        //Note!!! EventObserver handles events not Observer
        viewModel.errorEvent.observe(this, EventObserver { 
            errorMessage -> showErrorMessage(errorMessage)
        })
    }
    ...
}
rojarand
  • 445
  • 6
  • 18