我有这样一个用例,其中来自数据源的响应保证被消耗,并且在配置更改后不会丢失,但在已经消耗时也不会重复。StateFlow
似乎是最好的候选者,因为它保存了最后一个发出的值,但在以下场景中可能会出现问题:
1.数据源响应在每个请求上都有相同的错误(可能是由于本地缓存中没有数据或网络问题。
由于StateFlow
不发出相同的值,这可能会出现问题,在对数据源发出新请求后,如果先前的状态也是错误,则错误状态(可以是对话框)将不会再次显示在UI中。
将SharedFlow
与已配置的replay
一起使用
MutableSharedFlow<T>(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
字符串
这将表现得像LiveData
与repeatOnLifecycle
,但在以下场景中有自己的问题。
假设我们有这些状态
sealed class AssetState {
data class FetchAssetLoading(val assetList: List<AssetMinDataDomain>?) : AssetState()
data class FetchAssetSuccess(val assetList: List<AssetMinDataDomain>) : AssetState()
data class FetchAssetFailed(val msg: String, val assetList: List<AssetMinDataDomain>?) : AssetState()
}
型onCreate
或onViewCreated
内部
// Initial fetch
fetchData(param1, param2)
// Collecting the result of fetch data
with(viewModel) {
viewLifecycleOwner.collectShared(assetState, ::onAssetStateChanged)
}
型
扩展函数
inline fun <T : Any, L : SharedFlow<T>> LifecycleOwner.collectShared(
sharedFlow: L,
crossinline function: (T) -> Unit,
lifecycleState: Lifecycle.State = Lifecycle.State.STARTED
) {
lifecycleScope.launch {
repeatOnLifecycle(lifecycleState) {
sharedFlow.collect { t -> function(t) }
}
}
}
型
当发生配置更改时,当LifeCycle
至少达到STARTED
时,fetchData(param1, param2)
将被触发,其结果将被收集,但由于我们也使用repeatOnLifecycle
,因此将有两次数据发射。一次是作为请求fetchData
的结果,这是更更新的,另一次是作为repeatOnLifecycle
的结果,这可能是过时的。唯一的解决方案是我目前看到的是添加一个空状态或没有状态,然后在UI中接收到成功状态或失败状态后手动设置它,但似乎不是最好的解决方案,而且太重复了。有没有更好的方法来满足上述要求?谢谢
P.S
如果我在SharedFlow
中删除repeat = 1
,它将解决这个问题,但是如果活动转到onStop
,例如,用户在获取数据时按主页按钮,然后返回到应用程序,导致onStart
和onResume
触发,那么我们将丢失该事件及其结果。
1条答案
按热度按时间yzxexxkh1#
到目前为止,要使用流执行单个事件,请使用Channel并将其转换为常规冷流,如下所示
ViewModel
字符串
使用
send
来发射型
收集获取数据的结果
型
更新扩展功能
型
请注意,使用这种方法有一个微妙的问题,如果Channel发送了事件,但消费者突然根据设置的生命周期进入后台,您仍然可能错过事件。
参考:https://medium.com/androiddevelopers/viewmodel-one-off-event-antipatterns-16a1da869b95