我在我的应用程序中使用MutableLiveData进行基于事件的通信。我有单个活动两个片段的架构。
借助ViewModel,在Fragment-1中消耗LiveData事件。但是,当我使用菜单栏将此Fragment-1替换为Fragment-2,并最终返回到Fragment-1时,LiveData的旧值再次被捕获。
如何避免这个问题?非常感谢您提供任何帮助/建议!
谢谢。
我在我的应用程序中使用MutableLiveData进行基于事件的通信。我有单个活动两个片段的架构。
借助ViewModel,在Fragment-1中消耗LiveData事件。但是,当我使用菜单栏将此Fragment-1替换为Fragment-2,并最终返回到Fragment-1时,LiveData的旧值再次被捕获。
如何避免这个问题?非常感谢您提供任何帮助/建议!
谢谢。
Event
来包装 LiveData
的值,以便像下面这篇文章中所述那样处理其值的消耗:
https://medium.com/androiddevelopers/livedata-with-snackbar-navigation-and-other-events-the-singleliveevent-case-ac2622673150
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
}
假设您的LiveData值是一个字符串,那么单次事件的LiveData将会像这样:
val navigateToDetails = MutableLiveData<Event<String>>()
无论您在何处观察liveData,在onChanged
方法中通过调用myLiveDataObject.removeObservers(this);
来移除观察者。这将在第一次观察数据后移除观察者。
简单、清晰、可重用:
class Event<T>(val payload: T, var broadcasted: Boolean = false)
class MutableEventLiveData<T>: MutableLiveData<Event<T>>() {
fun postEvent(value: T) {
super.postValue(Event(value))
}
}
typealias EventLiveData<T> = LiveData<Event<T>>
class EventObserver<T>(private val broadcastCallback: (t: T)->Unit): Observer<Event<T>> {
override fun onChanged(e: Event<T>) {
if (!e.broadcasted) {
broadcastCallback(e.payload)
e.broadcasted = true
}
}
}
示例用法:
class YourViewModel : ViewModel() {
private val _errorEvent = MutableEventLiveData<String>()
val errorEvent: EventLiveData<String>
get() = _errorEvent
fun fireErrorEvent(errorMessage: String) {
_errorEvent.postEvent(errorMessage)
}
...
}
class YourActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
...
//Note!!! EventObserver handles events not Observer
viewModel.errorEvent.observe(this, EventObserver {
errorMessage -> showErrorMessage(errorMessage)
})
}
...
}