mickp
mickp

Reputation: 1809

Why is Livedata setValue ignored when called twice?

I have the following ViewModel with MutableLiveData data and another LiveData ones that is derived from data in a way that it updates its value only if the data.number is equal to 1.

class DummyViewModel : ViewModel() {

    private val data = MutableLiveData<Dummy>()
    val ones = data.mapNotNull { it.takeIf { it.number == 1 } }

    init {
        data.value = Dummy(1, "Init")
        doSomething()

    }

    fun doSomething() {
        data.value = Dummy(2, "Do something")
    }
}

data class Dummy(val number: Int, val text: String)

fun <T, Y> LiveData<T>.mapNotNull(mapper: (T) -> Y?): LiveData<Y> {
    val mediator = MediatorLiveData<Y>()
    mediator.addSource(this) { item ->
        val mapped = mapper(item)
        if (mapped != null) {
            mediator.value = mapped
        }
    }
    return mediator
}

I observe ones in my fragment. However, If I execute doSomething, I don't receive any updates in my fragment. If I don't execute doSomething, the dummy Init is correctly present in ones and I receive an update.

What is happening here? Why is ones empty and how can I overcome this issue?

Upvotes: 1

Views: 924

Answers (1)

Georgiy Shur
Georgiy Shur

Reputation: 840

Maybe I'm missing something, but the behavior seems like expected to me...

Lets' try to reproduce both cases sequentially.

Without doSomething() :

  1. Create Livedata
  2. Add Dummy(1, "Init")
  3. Start listening in the fragment: Because number is 1, it passes your filter and the fragment receives it

With doSomething():

  1. Create Livedata
  2. Add Dummy(1, "Init")
  3. Add Dummy(2, "Do something") (LiveData keeps only the last value, so if nobody observes, the first value is getting lost)
  4. Start listening in the fragment: Because number is 2, the value gets filtered and the fragment receives nothing

A little offtopic: it's always good to write tests for ViewModel cases like this, because you'll be able to isolate the problem and find the real reason quickly.

EDIT: also be aware that your filter is only working on observing, it isn't applied when putting the value into LiveData.

Upvotes: 2

Related Questions