如何停止多次触发 LiveData 事件
How to stop LiveData event being triggered more than Once
我在我的应用程序中使用 MutableLiveData 进行基于事件的通信。我有单个 activity 两个片段架构。
在 ViewModel 的帮助下,我正在使用 Fragment-1 中的 LiveData 事件。但是,当我使用菜单栏将此 Fragment-1 替换为 Fragment-2 并最终返回到 Fragment-1 时,LiveData 的旧值将再次被捕获。
如何避免这个问题?任何 help/suggestions 都非常感谢!
谢谢。
您可以使用 Event
包装 LiveData
值来处理使用其值的问题,如下文所示:
https://medium.com/androiddevelopers/livedata-with-snackbar-navigation-and-other-events-the-singleliveevent-case-ac2622673150
事件 class 会像:
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);
移除观察者
这将在观察到第一次数据后移除观察者。
接受答案的问题是你只能有一个观察者。
article 描述了具有多个观察者的解决方案。
我遇到了同样的问题,想出了这个库来解决它
https://github.com/ueen/LiveEvent
希望这对您有所帮助,祝您愉快!
简单、干净、可重复使用:
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)
})
}
...
}
我在我的应用程序中使用 MutableLiveData 进行基于事件的通信。我有单个 activity 两个片段架构。
在 ViewModel 的帮助下,我正在使用 Fragment-1 中的 LiveData 事件。但是,当我使用菜单栏将此 Fragment-1 替换为 Fragment-2 并最终返回到 Fragment-1 时,LiveData 的旧值将再次被捕获。
如何避免这个问题?任何 help/suggestions 都非常感谢! 谢谢。
您可以使用 Event
包装 LiveData
值来处理使用其值的问题,如下文所示:
https://medium.com/androiddevelopers/livedata-with-snackbar-navigation-and-other-events-the-singleliveevent-case-ac2622673150
事件 class 会像:
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);
移除观察者
这将在观察到第一次数据后移除观察者。
接受答案的问题是你只能有一个观察者。 article 描述了具有多个观察者的解决方案。
我遇到了同样的问题,想出了这个库来解决它 https://github.com/ueen/LiveEvent 希望这对您有所帮助,祝您愉快!
简单、干净、可重复使用:
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)
})
}
...
}