MVVM 中视图和 ViewModel 之间的通信与 LiveData

Pav*_*ley 11 android android-livedata android-architecture-components

ViewModel和之间进行通信的正确方法是什么ViewGoogle architecture components使用LiveData视图订阅更改并相应地更新自身,但这种通信不适用于单个事件,例如显示消息、显示进度、隐藏进度等。

有一些像SingleLiveEventGoogle 示例中的hack ,但它仅适用于 1 个观察者。一些开发人员使用EventBus但我认为当项目增长时它会很快失控。

有没有方便正确的实现方式,你是如何实现的?

(也欢迎 Java 示例)

pat*_*ist 4

是的,我同意,SingleLiveEvent这是一个 hacky 解决方案,EventBus(根据我的经验)总是会带来麻烦。

不久前,我ConsumableValue在阅读 Google CodeLabs for Kotlin Coroutines 时发现了一个名为的类,我发现它是一个很好、干净的解决方案,对我很有帮助(ConsumableValue.kt):

class ConsumableValue<T>(private val data: T) {
    private var consumed = false

    /**
     * Process this event, will only be called once
     */
    @UiThread
    fun handle(block: ConsumableValue<T>.(T) -> Unit) {
        val wasConsumed = consumed
        consumed = true
        if (!wasConsumed) {
            this.block(data)
        }
    }

    /**
     * Inside a handle lambda, you may call this if you discover that you cannot handle
     * the event right now. It will mark the event as available to be handled by another handler.
     */
    @UiThread
    fun ConsumableValue<T>.markUnhandled() {
        consumed = false
    }
}
Run Code Online (Sandbox Code Playgroud)
class MyViewModel : ViewModel {
    private val _oneShotEvent = MutableLiveData<ConsumableValue<String>>()
    val oneShotEvent: LiveData<ConsumableValue<String>>() = _oneShotData

    fun fireEvent(msg: String) {
        _oneShotEvent.value = ConsumableValue(msg)
    }
}
Run Code Online (Sandbox Code Playgroud)
// In Fragment or Activity
viewModel.oneShotEvent.observe(this, Observer { value ->
    value?.handle { Log("TAG", "Message:$it")}
})
Run Code Online (Sandbox Code Playgroud)

简而言之,该handle {...}块只会被调用一次,因此如果您返回屏幕,则无需清除该值。