如何在Android中以多种方式观察livedata并进行正确观察?

时间:2019-09-24 07:09:43

标签: android android-fragments android-livedata mutablelivedata

我有一个Activity,它将变为片段A,然后变为片段B,如下所示。

Activity -> Fragment-A -> Fragment-B

情况1

这两个片段观察到相同的LiveData,以显示如下所示的SnackBar。

viewModel.responseData.observe(this, Observer {
            it.getContentIfNotHandled()?.let {
            showSnackBar(it)
}

viewModel中的livedata

var responseData = MutableLiveData<Event<String>>()
responseData.value = Event("$message")

错误: 当我使用上面的代码。它仅在片段A 中显示snackBar片段B 无法获取该值。

情况2

当我将代码更改为以下内容

viewModel.responseData.observe(this, Observer {
            showSnackBar(it.peekContent())
})

两个片段都可以获取值。

错误:

关闭片段后,再次旋转。因为responseData的值仍然存在,所以显示了snackBar。 但是我没有发送消息。

来自Google的

Event类参考如下:

/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package bbin.mobile.ballbet.support

import androidx.lifecycle.Observer
import timber.log.Timber

/**
 * 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
}

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

我希望片段为他们显示正确的SnackBar消息。

如何在Android中以正确的方式观察livedata的多个片段?

谢谢。

1 个答案:

答案 0 :(得分:0)

您正在正确地观察LiveData,这是Event类的设计方式。

完成时

viewModel.responseData.observe(this, Observer {
            it.getContentIfNotHandled()?.let {
            showSnackBar(it)
}

getContentIfNotHandled仅返回一次内容,直到再次设置新值为止。如果FragmentA消耗了该第一FragmentB,则将无法消耗相同的值。这是peekContent起作用的原因,因为即使事件已被使用,它将始终返回当前值。

如果有确凿的理由需要在两个片段中都显示此Snackbar消息,建议您在每个片段的LiveData实例上进行观察。

您可以通过在每次调用LiveData<Event<String>>时返回一个新的viewModel.getResponseData()来做到这一点。