我有一个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。
但是我没有发送消息。
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
的多个片段?
谢谢。
答案 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()
来做到这一点。