如何让LiveData在另外两个LiveData之间切换
How to get LiveData to switch between two other LiveData
我有以下场景。播客可以来自互联网或本地 (db) 都是 LiveData
// Live
private val _live = MutableLiveData<List<Podcast>>()
val live: LiveData<List<Podcast>> = _live
// Local
val local: LiveData<List<Podcast>> = dao.observePodcasts()
// Combined
val podcasts: LiveData<List<Podcast>> = ...
我的问题是:- 我怎样才能只使用一个 LiveData podcasts
以便按需从实时或本地获取数据
fun search(query: String) {
// podcasts <- from live
}
fun subcribed() {
// podcasts <- from local
}
我个人在 projects 中使用 MediatorLiveData 来实现您所描述的相同功能。
直接从文档中引用,因为它们非常简单...
Consider the following scenario: we have 2 instances of LiveData, let's name them liveData1 and liveData2, and we want to merge their emissions in one object: liveDataMerger. Then, liveData1 and liveData2 will become sources for the MediatorLiveData liveDataMerger and every time onChanged callback is called for either of them, we set a new value in liveDataMerger.
LiveData liveData1 = ...;
LiveData liveData2 = ...;
MediatorLiveData liveDataMerger = new MediatorLiveData<>();
liveDataMerger.addSource(liveData1, value -> liveDataMerger.setValue(value));
liveDataMerger.addSource(liveData2, value -> liveDataMerger.setValue(value));
在这种情况下,您可以使用 MediatorLiveData
。
您需要使用 MediatorLiveData
做的是需要 LiveData
源能够侦听对 LiveData
源的更改。
尝试以下操作:
YourViewModel.kt
private val _podcasts = MediatorLiveData<List<Podcast>>().apply {
addSource(_live) { dataApi ->
// Or you can do something when `_live` has a change in value.
if(local.value == null) {
this.value = dataApi
}
}
addSource(local) { dataLocal ->
// Or you can do something when `local` has a change in value.
if(_live.value == null) {
this.value = dataLocal
}
}
}
val podcasts: LiveData<List<Podcast>> = _podcasts
如前所述,这可以通过 MediatorLiveData
完成。另一种选择是使用 Flows 而不是组合 LiveData。
val podcasts = combine(local, live) { local, live ->
// Add your implementation of how you would like to combine them
live ?: local
}.asLiveData(viewModelScope.coroutineContext)
如果您使用的是 Room,只需将 return 类型更改为 Flow 即可获得 Flow 结果。对于 MutableLiveData,您可以将其替换为 MutableStateFlow。
使用MediatorLiveData
并没有像我预期的那样满足我的需求,因为我希望能够随时在本地和实时之间切换!
所以我做了如下实现
enum class Source {
LIVE, LOCAL
}
private val _live = MutableLiveData<List<Podcast>>()
private val _local = dao.observePodcasts()
private val source = MutableLiveData<Source>(Source.LOCAL)
// Universal
val podcasts: LiveData<List<Podcasts>> = source.switchMap {
liveData {
when (it) {
Source.LIVE -> emitSource(_live)
else -> emitSource(_local)
}
}
}
emitSource() removes the previously-added source.
然后我实现了下面两个方法
fun goLocal() {
source.postValue(Source.LOCAL)
}
fun goLive() {
source.postValue(Source.LIVE)
}
然后我会在实时或本地存储中向观察者调用受尊重的函数
用例之一
searchItem.setOnActionExpandListener(object : MenuItem.OnActionExpandListener {
override fun onMenuItemActionExpand(p0: MenuItem?): Boolean {
viewModel.goLive()
return true
}
override fun onMenuItemActionCollapse(p0: MenuItem?): Boolean {
viewModel.goLocal()
return true
}
})
我有以下场景。播客可以来自互联网或本地 (db) 都是 LiveData
// Live
private val _live = MutableLiveData<List<Podcast>>()
val live: LiveData<List<Podcast>> = _live
// Local
val local: LiveData<List<Podcast>> = dao.observePodcasts()
// Combined
val podcasts: LiveData<List<Podcast>> = ...
我的问题是:- 我怎样才能只使用一个 LiveData podcasts
以便按需从实时或本地获取数据
fun search(query: String) {
// podcasts <- from live
}
fun subcribed() {
// podcasts <- from local
}
我个人在 projects 中使用 MediatorLiveData 来实现您所描述的相同功能。
直接从文档中引用,因为它们非常简单...
Consider the following scenario: we have 2 instances of LiveData, let's name them liveData1 and liveData2, and we want to merge their emissions in one object: liveDataMerger. Then, liveData1 and liveData2 will become sources for the MediatorLiveData liveDataMerger and every time onChanged callback is called for either of them, we set a new value in liveDataMerger.
LiveData liveData1 = ...;
LiveData liveData2 = ...;
MediatorLiveData liveDataMerger = new MediatorLiveData<>();
liveDataMerger.addSource(liveData1, value -> liveDataMerger.setValue(value));
liveDataMerger.addSource(liveData2, value -> liveDataMerger.setValue(value));
在这种情况下,您可以使用 MediatorLiveData
。
您需要使用 MediatorLiveData
做的是需要 LiveData
源能够侦听对 LiveData
源的更改。
尝试以下操作:
YourViewModel.kt
private val _podcasts = MediatorLiveData<List<Podcast>>().apply {
addSource(_live) { dataApi ->
// Or you can do something when `_live` has a change in value.
if(local.value == null) {
this.value = dataApi
}
}
addSource(local) { dataLocal ->
// Or you can do something when `local` has a change in value.
if(_live.value == null) {
this.value = dataLocal
}
}
}
val podcasts: LiveData<List<Podcast>> = _podcasts
如前所述,这可以通过 MediatorLiveData
完成。另一种选择是使用 Flows 而不是组合 LiveData。
val podcasts = combine(local, live) { local, live ->
// Add your implementation of how you would like to combine them
live ?: local
}.asLiveData(viewModelScope.coroutineContext)
如果您使用的是 Room,只需将 return 类型更改为 Flow 即可获得 Flow 结果。对于 MutableLiveData,您可以将其替换为 MutableStateFlow。
使用MediatorLiveData
并没有像我预期的那样满足我的需求,因为我希望能够随时在本地和实时之间切换!
所以我做了如下实现
enum class Source {
LIVE, LOCAL
}
private val _live = MutableLiveData<List<Podcast>>()
private val _local = dao.observePodcasts()
private val source = MutableLiveData<Source>(Source.LOCAL)
// Universal
val podcasts: LiveData<List<Podcasts>> = source.switchMap {
liveData {
when (it) {
Source.LIVE -> emitSource(_live)
else -> emitSource(_local)
}
}
}
emitSource() removes the previously-added source.
然后我实现了下面两个方法
fun goLocal() {
source.postValue(Source.LOCAL)
}
fun goLive() {
source.postValue(Source.LIVE)
}
然后我会在实时或本地存储中向观察者调用受尊重的函数
用例之一
searchItem.setOnActionExpandListener(object : MenuItem.OnActionExpandListener {
override fun onMenuItemActionExpand(p0: MenuItem?): Boolean {
viewModel.goLive()
return true
}
override fun onMenuItemActionCollapse(p0: MenuItem?): Boolean {
viewModel.goLocal()
return true
}
})