当我使用repeatOnLifecycle
收集Activity/Fragment中的StateFlow,然后导航到另一个Activity,然后返回到基本Activity时,即使我不更新stateFlow,流也会重新收集。
例如:
- 在视图模型中**
private var _deletionStatusStateFlow = MutableStateFlow(0)
val deletionStatusStateFlow = _deletionStatusStateFlow.asStateFlow()
然后我在片段中观察到:
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED){
deleteAccountViewModel.deletionStatusStateFlow.collect {
if (it == 1){
startActivity(AnyActivity)
}
}
}
}
- 每次单击BackKey时,活动都保持打开状态**
但如果我使用相同示例的LiveData ......观察块将不会再次执行(当返回到片段视图中的STATRED状态时)
如何在StateFlow中实现与LiveData类似的行为?
有一个简单用法的解决方案:我使用flowWithLifecycle(...).distinctUntilChanged()
时就是这样,但这很复杂:
val results: StateFlow<SearchResult> =
queryFlow.mapLatest { query ->
repository.search(query)
}.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5000L),
initialValue = SearchResult.EMPTY
)
上游将被重新生成(并且这将花费上游repo读取)
3条答案
按热度按时间64jmpszr1#
这是预期的行为,因为Activity和Fragments可以被多次重新创建,这就是
repeatOnLifecycle
存在的原因。您需要将数据 Package 在一个类中,该类还具有一个布尔属性,指示关联的导航事件是否已发生。Activity/Fragment中的收集器在执行导航事件时,还应调用ViewModel函数,ViewModel使用该函数更新Flow以发出一个事件,在该事件中导航事件被视为已处理。这对于
stateIn
来说太复杂了。我希望使用MutableStateFlow,这样您就可以根据来自Activity的反馈更新值。此过程在此处的Android文档中进行了描述。
a2mppw5e2#
导航通常最好用常规
Flow
表示(或SharedFlow
),而不是StateFlow
。导航事件只应被收集器使用一次,然后丢弃,这与可以随意重新读取的UI状态相反。如果不丢弃该事件(一个Flow
为你做这件事)你会得到你所看到的行为,其中导航被触发多次。考虑到这一点,我将从视图模型中将导航公开为
Flow
,与您可能拥有的任何UI状态流分开。如果这个视图模型有不止一种类型的导航事件,那么您将希望清楚地定义它们,如下所示。
现在,我们将收集从Activity的视图模型中公开的流。
仅供参考,这是来自状态流的Kotlin文档
与使用流构建器构建的冷流不同,StateFlow是热流:从流中收集不会触发任何生产者代码。
这意味着,只要您将结果存储在视图模型某处的
StateFlow
中,就不会重新触发对repo的上游调用。busg9geu3#
尝试将生命周期从已启动更改为已创建
到这个代码
前者告诉
repeatOnLifecycle
在生命周期至少开始时重复collect
,这意味着每次生命周期处于开始状态时,它都将重新收集所述流与
repeatOnLifecycle(Lifecycle.State.STARTED)
不同,后者仅在生命周期处于CRATED状态时重新收集流,这仅发生在创建片段CMIMW时