ViewModel Live Data observers calling on rotation

Viewed 337

In my view model, I have two properties:

private val databaseDao = QuestionDatabase.getDatabase(context).questionDao()
val allQuestions: LiveData<List<Question>> = databaseDao.getAllQuestions()

I have observers set on "allQuestions" in my fragment and I'm noticing the observer is being called when I rotate the device. Even though the View Model is only being created once (can tell via a log statement in init()), the observer methods are still being called.

Why is this? I would think the point is to have persistency in the View Model. Ideally, I want the database questions to be only loaded once, regardless of rotation.

3 Answers

This happens because LiveData is lifecycle aware.
And When you rotate the screen you UI Controller [Activity/Fragment] goes through various lifecycle states and lifecycle callbacks.
And since LiveData is lifecycle aware, it updates the detail accordingly.

I have tried to explain this with following points:

  1. When the UI Controller is offscreen, Live Data performs no updates.
  2. When the UI Controller is back on screen, it gets current data.
    (Because of this property you are getting above behavior)
  3. When UI controller is destroyed, it performs cleanup on its own.
  4. When new UI Controller starts observing live data, it gets current data.

add this check inside observer

if(lifecycle.currentState == Lifecycle.State.RESUMED){

//code

}

I have the same issue, after reading the jetpack guideline doc, I solve it. Just like what @SVK mentioned, after the rotation of the screen, activity/fragment were re-created. Base on the solution https://stackoverflow.com/a/64062616,

class SingleLiveEvent<T> : MutableLiveData<T>() {

val TAG: String = "SingleLiveEvent"

private val mPending = AtomicBoolean(false)

@MainThread
override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {

    if (hasActiveObservers()) {
        Log.w(TAG, "Multiple observers registered but only one will be notified of changes.")
    }

    // Observe the internal MutableLiveData
    super.observe(owner, Observer<T> { t ->
        if (mPending.compareAndSet(true, false)) {
            observer.onChanged(t)
        }
    })
}

override fun observeForever(observer: Observer<in T>) {
    if (hasActiveObservers()) {
        Log.w(TAG, "Multiple observers registered but only one will be notified of changes.")
    }

    // Observe the internal MutableLiveData
    super.observeForever { t ->
        if (mPending.compareAndSet(true, false)) {
            observer.onChanged(t)
        }
    }
}

@MainThread
override fun setValue(@Nullable t: T?) {
    mPending.set(true)
    super.setValue(t)
}

/**
 * Used for cases where T is Void, to make calls cleaner.
 */
@MainThread
fun call() {
    value = null
}
Related