In the end, I found a workaround for this problem. I had to move away from the live data that emits a single event since it couldn't behave the way I needed it to behave.
Instead of this, I used simple mutable live data which emits an event object which wraps a data as in the last paragraph of this article by Jose Alcérreca.
I'm showing fragments in a view pager so I have only one visible fragment at the time.
So my view model looks like this:
class ActionViewModel : ViewModel() {
private val onCreateLiveData: MutableLiveData<Event<String>> = MutableLiveData()
fun observeOnCreateEvent(): LiveData<Event<String>> = onCreateLiveData
fun onCreateCollectionClick(message: String) {
this.onCreateLiveData.value = Event(message)
}
}
Event wrapper class implementation looks like this:
/*Used as a wrapper for data that is exposed via a LiveData that represents an
event.*/
open class Event<out T>(private val content: T) {
var hasBeenHandled = false
private set // Allow external read but not write
/**
* Returns the content and prevents its use again.
*/
fun getContentIfNotHandled(): T? {
return if (hasBeenHandled) {
null
} else {
hasBeenHandled = true
content
}
}
/**
* Returns the content, even if it's already been handled.
*/
fun peekContent(): T = content
}
In fragments now we can observe events like this:
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
actionViewModel = ViewModelProviders.of(requireActivity()).get(ActionViewModel::class.java)
actionViewModel.observeOnCreateEvent()
.observe(this, Observer {
it?.takeIf { userVisibleHint }?.getContentIfNotHandled()?.let {
//DO what ever is needed
}
})
}
Fragment userVisibleHint property will return true if the fragment is currently visible to the user. Since we are only showing one fragment at the time this works for us. This means that the fragment will only access the event data if it is visible.
Also, implementation of the Event wrapper allows only one read of the value, so that every next time Observer gets this event, its value will be null and we'll ignore it.
Conclusion: This way we are simulating a single event live data which notifies only last subscribed observer.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…