Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MutableLiveData setValue: Unexpected behavior in Activity's onCreate

I'm toying with MutableLiveData's methods to figure out what triggers the observer and what doesn't.

Right now, I have this Activity:

class ActivityA : AppCompatActivity() {
    private val liveData = MutableLiveData<Int>().apply { this.value = 10 }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        liveData.observe(this, Observer {
            Log.v("ActivityA", "liveData = $it")
        })
        Log.v("ActivityA", "liveData = ${liveData.value}")
        liveData.value = 11
        liveData.postValue(12)
        liveData.value = 13
    }
}

The output is the following:

liveData = 10
liveData = 13
liveData = 12

Shouldn't it be this?

liveData = 10
liveData = 11
liveData = 13
liveData = 12
like image 742
Vegas Avatar asked Oct 28 '22 02:10

Vegas


1 Answers

Your problem is that livedata observer is not active. because of this when you do liveData.value = 11, this value doesn't get posted to the observer. and subsequently when you do liveData.value = 13 it overrides the value 11.

To check if your live data has any active observers, you can do liveData.hasActiveObservers()

Docs clearly state that setValue only dispatches if there are any active observers

void setValue (T value)

Sets the value. If there are active observers, the value will be dispatched to them.

But why your observer is not active?

When you set a value, LiveData internally uses ObserverWrapper's shouldBeActive method to check if a specific observer is active .

and when you use observe method to register your observer, the observer is wrapped in a LifecycleBoundObserver (subclass of ObserverWrapper) which defines its shouldBeActive as follows.

@Override
boolean shouldBeActive() {
   return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}

The part that matters is .isAtLeast(STARTED), here STARTED is of type Lifecycle.State, and its documentation has following to say about it.

Started state for a LifecycleOwner. For an Activity, this state is reached in two cases:

after onStart call;

right before onPause call.

and because you register observer in onCreate, it doesn't become active right away and hence the problem.

For verification you can also use the observeForever (please read its documentation, it differs greatly from observe) method to register your observer. because this method makes the observer active instantly, you will see the output that you expect.

liveData.observeForever {
    Log.v("ActivityA", "liveData = $it")
}
like image 115
mightyWOZ Avatar answered Nov 26 '22 09:11

mightyWOZ