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
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 threadIF you will change to fastLiveData.setValue(x)
you will get the behaviour you want.
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"
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With