I have a setup where an Activity holds two fragments (A, B), and B has a ViewPager with 3 Fragments (B1, B2, B3)
In the activity (ViewModel) I observe a model (Model) from Room, and publish the results to a local shared flow.
val mSharedFlow = MutableSharedFlow<Model>` that I publish the model updates to:
...
viewModelScope.launch { repo.observeModel().collect(sharedFlow) }
Fragments A and B (ViewModels) have access to the sharedFlow through (Parent) fun getModelFlow(): Flow<Model>
There are no problems running the collects for each Fragment:
viewModelScope.launch {
parent.getModelFlow().collect { model -> doStuff(model) }
}
But, the problem is in the nested fragments (B1 etc.)
In the fragment (ViewModel) for B1 I have another parent.getModelFlow() that in turn calls Fragment B (ViewModel) parent.getParentFlow()
I have no problem acquiring the flow (i.e the SharedFlow (as Flow from the activity ViewModel)); But the collect in B1 does nothing.
- Why am I not able to collect from the shared flow in the nested B1? (When A and B works fine)
- Am I already not taking some flow rules into consideration? Additional
launch{}'es, otherwithContexts(Some?),flowOn,launchInetc.?
(The providing of the flow is not the problem. Even if I create intermediary flows, or place the sharedFlow in a kotlin Singleton object I still have the same problem)
=== EDIT ===
I was asked to add more information, unfortunately (for all) I can't paste the actual code because it would just appear verbose and foreign (see my comment below). But here's some psuedo-code that should be equivalent.
One clarification, that you can see below, Activity, FragmentA, FragmentB, FragmentB1 (etc.) are all running at the same time- but only one of A and B is visible at one time.
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?