Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android : Live Data skipping values

I am using Live Data to publish states from View Model to Fragments, this might result in states getting published frequently. But the Mutable Live Data is skipping the initial values and taking the latest value available.

There is an article which talks about this characteristic, but is there a way of handling this case, such as Flowable in RxJava or setting Back Pressure Strategy or will I need to go back to using RxJava and handle Life-cycle based publishing?

Following is a sample code which shows this behaviour. Values from 1 to 10 are published but only two values are received, 0 and 10. Can we change this behaviour in Live Data or should I use RxJava for this purpose?

Fragment (Subscriber) :

class ParentFragment : Fragment() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        viewModel = ViewModelProviders.of(
            this, ParentViewModelFactory(this, null)
        ).get(ParentViewModel::class.java)

        viewModel.fastLiveData.observe(this, Observer {
            Timber.i(it.toString())
        })

        viewModel.startPublishing()
    }
}

View Model (Publisher):

class ParentViewModel(private val savedState : SavedStateHandle)
    : ViewModel<ParentState>() {

    val fastLiveData : MutableLiveData<Int> = MutableLiveData(0)

    fun startPublishing() {
        for(x in 1..10) {
            Timber.i(x.toString())
            fastLiveData.postValue(x)
        }
    }
}

Output :

(ParentViewModel.kt:30)#startPublishing: 1
(ParentViewModel.kt:30)#startPublishing: 2
(ParentViewModel.kt:30)#startPublishing: 3
(ParentViewModel.kt:30)#startPublishing: 4
(ParentViewModel.kt:30)#startPublishing: 5
(ParentViewModel.kt:30)#startPublishing: 6
(ParentViewModel.kt:30)#startPublishing: 7
(ParentViewModel.kt:30)#startPublishing: 8
(ParentViewModel.kt:30)#startPublishing: 9
(ParentViewModel.kt:30)#startPublishing: 10
(ParentFragment.kt:57)#onChanged: 0
(ParentFragment.kt:57)#onChanged: 10
like image 800
ashwin mahajan Avatar asked Mar 04 '23 07:03

ashwin mahajan


2 Answers

The reason is you are using postValue()

  • postValue will set the value on background thread, and it will set the latest value in case of a lot of emission.
  • setValue will set your value on main thread

IF you will change to fastLiveData.setValue(x) you will get the behaviour you want.

like image 171
Mustafa Ozhan Avatar answered Mar 08 '23 12:03

Mustafa Ozhan


Coroutines bring a solution to this:

Example:

events.value = "Event A"
events.value = "Event B"
events.value = "Event C"

This, indeed only populates "Event C" to the observer.

However, if you wrap your code with coroutine, it's gonna work:

viewModelScope.launch(Dispatchers.Main) {
    events.value = "Event A"
    events.value = "Event B"
    events.value = "Event C"
}
like image 31
Jacek Kwiecień Avatar answered Mar 08 '23 11:03

Jacek Kwiecień