我有一個設定,其中一個 Activity 包含兩個片段(A、B),而 B 有一個帶有 3 個片段(B1、B2、B3)的 ViewPager
在活動 (ViewModel) 中,我Model從 Room 觀察模型 (),并將結果發布到本地共享流。
val mSharedFlow = MutableSharedFlow<Model>` that I publish the model updates to:
...
viewModelScope.launch { repo.observeModel().collect(sharedFlow) }
Fragments A 和 B (ViewModels) 可以通過 (Parent) 訪問 sharedFlowfun getModelFlow(): Flow<Model>
為每個 Fragment 運行收集沒有問題:
viewModelScope.launch {
parent.getModelFlow().collect { model -> doStuff(model) }
}
但是,問題出在嵌套片段(B1 等)中。在 B1 的片段(ViewModel)中,我有另一個parent.getModelFlow()又呼叫片段 B(ViewModel)parent.getParentFlow()
我獲取流沒有問題(即 SharedFlow(作為來自活動 ViewModel 的流));但是collectin B1 什么都不做。
- 為什么我無法從嵌套 B1 中的共享流中收集?(當 A 和 B 作業正常時)
- 我是否已經沒有考慮到一些流程規則?附加
launch{}'es,其他withContexts(Some?),flowOn等等launchIn?
(提供流不是問題。即使我創建中間流,或者將 sharedFlow 放在 kotlin Singleton 物件中,我仍然有同樣的問題)
===編輯===
我被要求添加更多資訊,不幸的是(對于所有人)我無法粘貼實際代碼,因為它只會顯得冗長和陌生(請參閱下面的評論)。但是這里有一些應該等效的偽代碼。
一個澄清,您可以在下面看到,Activity、FragmentA、FragmentB、FragmentB1 (等)都在同時運行 - 但一次只有 A 和 B 之一可見。
class TheActivity {
fun onCreate() {
setupFragments()
}
/** Two fragments active at the same time,
but only one FrameLayout is visible at one time */
private fun setupFragments() {
val a = FragmentA.newInstance()
val b = FragmentB.newInstance()
supportFragmentManager.commit {
add(R.id.fragment_holder_a, a)
add(R.id.fragment_holder_b, b)
}
}
}
class ActivityViewModel {
val activityModelFlow = MutableSharedFlow<Model>()
fun start() {
viewModelScope.launch {
getRoomFlow(id).collect(activityModelFlow)
}
}
}
class FragmentA { // Not very interesting
val viewModel: ViewModelA
}
class ViewModelA {
fun start() {
viewModelScope.launch {
parentViewModel.activityModelFlow.collect { model ->
log("A model: $model")
}
}
}
}
class FragmentB {
val viewModel: ViewModelB
val viewPagerAdapter = object : PagesAdapter.Pages {
override val count: Int = 1
override fun title(position: Int): String = "B1"
override fun render(position: Int): Fragment = FragmentB1.newInstance()
}
}
class ViewModelB {
val bModelFlow: Flow<Model> get() = parentViewModel.activityModelFlow
fun start() {
viewModelScope.launch {
parentViewModel.activityModelFlow.collect { model ->
log("B model: $model")
}
}
}
}
class Fragment B1 {
val viewModel: ViewModelB1
}
class ViewModelB1 {
fun start() {
viewModelScope.launch {
// in essence:
// - ViewModelB.bModelFlow ->
// - ActivityViewModel.modelFlow
parentViewModel.bModelFlow.collect { model ->
log("B1 model: $model")
}
}
}
}
So, all of the connections of acquiring parentViewModels, DI, fragment creation etc. is all working fine. But B1 model: $model is never called! Why?
uj5u.com熱心網友回復:
這與片段、生命周期、流和協程阻塞幾乎沒有(讀無)聯系——我認為這是背后的原因。
val activityModelFlow = MutableSharedFlow<Model>()
// is the same as
val activityModelFlow = MutableSharedFlow<Model>(
replay = 0,
extraBufferCapacity = 0,
onBufferOverflow = BufferOverflow.SUSPEND
)
這意味著新訂閱者將可以訪問0(!)存盤在重播快取中的值。因此,當 FragmentB1 開始訂閱時,模型已經發出。
解決方案(沒有任何優化或進一步考慮)
private val bulletFlow = MutableSharedFlow<Bullet>(replay = 1)
(或使用 StateFlow,但我不想打擾初始狀態/值)
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/424649.html
