5

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
Vegas
  • 8,017
  • 1
  • 10
  • 14
  • 1
    it seems maybe he just copied that answer from here https://stackoverflow.com/questions/51299641/difference-of-setvalue-postvalue-in-mutablelivedata – Ashwini Saini Jan 31 '20 at 14:07
  • Can you move last three line to onStart method and try again ? – toffor Jan 31 '20 at 14:40

1 Answers1

3

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")
}
mightyWOZ
  • 7,946
  • 3
  • 29
  • 46
  • What is still strange about this is that if you remove the `postValue(12)` and the `setValue = 13`, then it WILL print 11, so it DOES have an observer when you do `setValue = 11` but only if you dont `postValue(12)`? – Quinn Jan 31 '20 at 14:32
  • Actually that makes sense, its just getting over ridden before it gets an active observer, but the observer isn't active when its set to 11, you're right – Quinn Jan 31 '20 at 14:34
  • Yes, Observer only becomes active if the lifecycle is started. – EpicPandaForce Jan 31 '20 at 17:09