0

我正在使用 SingleLiveEvent 来传达我的 ViewModel 和我的活动。类似的东西(伪代码):

    class MyActivity: BaseActivity{


fun onCreate(){
//Init viewmodel and so on
 viewModel.commands.observe(this, { command ->
            logger.debug("Command received","------>>>>>>>"+command.javaClass.simpleName)
            processCommand(command)
        })

}

}

我的 ViewModel 是这样的:

class MyViewModel(application: Application) : BaseAndroidViewModel(application) {

val command: SingleLiveEvent<CustomCommands> = SingleLiveEvent()

init{

loadOneThing()
command.postValue(CustomCommands.MessageCommand("one thing loaded"))

loadAnotherThing()
command.postValue(CustomCommands.MessageCommand("another thing loaded"))

}
}

我遇到的问题是 Activity 只接收最后一个命令,这是按照设计的。SingleLiveEvent 是来自 LiveData 的 Child 类,文档对 postValue 方法进行了以下说明:

  • * 如果您在主线程执行发布的任务之前多次调用此方法,则 * 只有最后一个值会被分派。

有趣的是,如果我在发布命令的行上设置断点,模拟器/设备/主线程有足够的时间来处理第一个命令,并且第二个命令也会被发送。但是在没有断点的情况下执行应用程序时,如果视图模型在命令之间执行的任务非常快(没有休息请求或类似的事情,但有一些计算),主线程没有足够的时间来完成第一个命令,并且第二个命令被忽略。

但我真的需要 View 来接收 ViewModel 发送的所有事件/命令。

我想 SingleLiveEvent 不是该用例的正确工具,LiveData 也不是,因为在设备旋转时重新发送已经消耗的事件等问题。

有人知道更好的方法来做到这一点吗?

提前致谢!

4

2 回答 2

0

你试过使用 EventObserver 吗?

/**
 * 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) {

    @Suppress("MemberVisibilityCanBePrivate")
    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
}

/**
 * An [Observer] for [Event]s, simplifying the pattern of checking if the [Event]'s content has
 * already been handled.
 *
 * [onEventUnhandledContent] is *only* called if the [Event]'s contents has not been handled.

*/

class EventObserver<T>(private val onEventUnhandledContent: (T) -> Unit) : Observer<Event<T>> {
    override fun onChanged(event: Event<T>?) {
        event?.getContentIfNotHandled()?.let {
            onEventUnhandledContent(it)
        }
    }
}

将其与实时数据一起使用

val someEvent: MutableLiveData<Event<Unit>>= MutableLiveData()

当你需要一些活动时

fun someEventOccured(){
   someEvent.value = Event(Unit)
}

分片文件,观察事件

viewModel.someEvent.observe(this, EventObserver {
    //somecode
})
于 2021-05-23T17:07:44.233 回答
0

我今天遇到了同样的问题。我还将 SingleLiveEvent 用于命令/事件。我已经解决了这个问题

commands.value = event而不是commands.postValue(event). 然后我想知道为什么它会这样。我找到了这篇文章。在文章中,

但是对于 postValue,值会更新两次,观察者收到通知的次数取决于主线程的执行情况。例如,如果 postValue 在主线程执行前被调用了 4 次,那么观察者将只收到一次通知,并且会收到最新更新的数据,因为要发送的通知被安排在主线程上执行. 因此,如果您在执行主线程之前多次调用 postValue 方法,那么最后传递的值(即最新值)将被分派到主线程,其余值将被丢弃。

我希望它可以帮助遇到同样问题的人。

于 2022-02-10T20:22:47.577 回答