【问题标题】:How to observe the livedata with multiple observe for correct way in Android?如何在Android中以正确的方式通过多次观察来观察实时数据?
【发布时间】:2019-09-24 07:09:43
【问题描述】:

我有一个Activity,它会转到fragment-A,然后转到fragment-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")

错误: 当我使用上面的代码时。它仅在 fragment-A 处显示 snackBarfragment-B 无法获取值。

情况2

当我将代码更改为以下时

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

两个fragment都可以取到值。

错误:

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

来自 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)
        }
    }
}

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

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

提前致谢。

【问题讨论】:

  • 浏览这个博客你就会知道。 blog.mindorks.com/…
  • 请贴出viewmodel初始化代码
  • 事件仅用于通知单个时间值,因此当您再次返回相同片段时,除非将新事件添加到 livedata,否则不会再次收到相同值的通知。
  • @JeelVankhede 当使用 peekContent 时,它会。
  • 请出示Event

标签: android android-fragments android-livedata mutablelivedata


【解决方案1】:

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

当你这样做时

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

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

如果有充分的理由需要在两个片段中显示此 Snackbar 消息,我建议您观察每个片段的不同 LiveData 实例。

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

【讨论】:

  • 这很奇怪.. 在 java 中使用共享 liveDatas 时,我从来不必使用 peekContent,尽管它总是正常工作。
  • 你不应该依赖peekContent,因为它违背了创建Event类的目的
  • 是的,我不是。我也没有使用事件策略。但我很确定我已经有一个 ViewModel,它有一个被几个 Fragment 观察到的 LiveData,它们都在正确更新,所以我不明白为什么它不适用于 OP
  • 哦,我明白了,OP 已经使用了这个 Event 类,所以这就是它不起作用的原因。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-04
  • 2017-04-06
  • 1970-01-01
  • 2011-06-17
  • 2020-05-13
  • 2012-05-11
相关资源
最近更新 更多