In <https://medium.com/androiddevelopers/a-safer-way-to-collect-flows-from-android-uis-23080b1f8bda>...
c
In https://medium.com/androiddevelopers/a-safer-way-to-collect-flows-from-android-uis-23080b1f8bda Google recommends using
repeatOnLifecycle
for Flow collection within
onViewCreated
of Fragments. But there’s a catch to it: when I navigate to another Fragment, the previous Fragment goes to
ON_DESTROY_VIEW
but returns to
ON_VIEW_CREATED
state when I navigate back to it. Since
repeatOnLifecycle
will only fully terminate itself when the Fragment reached
ON_DESTROY
state, the call to
repeatOnLifecycle
in
onViewCreated
will spawn a DUPLICATE Flow collection. When I repeat this navigation / back navigation, even more Flow collections will add up. The solutions I considered are: a) using
asLiveData()
in the ViewModel b) moving
repeatOnLifecycle
calls to
onCreate
of the Fragment But I wonder why Google recommends using
repeatOnLifecycle
in
onViewCreated
. Can anyone shed some light on this?
z
If you call
repeatOnLifecycle
on
viewLifecycleOwner
as described in the article, then the collection should be tied to the lifecycle of the Fragment's view, which means that it will be terminated when
onDestroyView
happens.
☝️ 2
r
Something you may have missed from that article (was briefly mentioned but not really explictly) is that the Flow from the ViewModel should (always?) be a StateFlow (either directly from MutableStateFlow or via another flow using stateIn)
In this way you are correct that the flow will get recollected but that just means the last value will get replayed and no new work will happen
a
The flow doesn't necessarily have to be a state flow (hot flow). If you have a flow of location information or a flow that starts a web socket, you may want to use a cold flow to avoid unnecessary work when the screen is in the back stack.
c
Thank you all for your feedback! I will answer separately: @zsmb The problem is not that the collection doesn’t stop (which it actually does!) but that due to the Fragment lifecycle (after
onDestroyView
we can get back to
onViewCreated
) multiple
repeatOnLifecycle
calls are issued which add up one after the other. @Robert Williams Even if the
Flow
from the ViewModel is a
StateFlow
, still multiple collections will be launched which lead to multiple UI updates which is a bad thing since my application will become slower and slower after each navigation back to that Fragment. I still think, that
onCreateView
is the wrong place to call
repeatOnLifecycle
.
r
This is already handled by repeatOnLifecycle. From the docs:
* Runs the given [block] in a new coroutine when
this
[Lifecycle] is at least at [state] and
* suspends the execution until
this
[Lifecycle] is [Lifecycle.State.DESTROYED].
So as long as you're using the
viewLifecycleOwner
scope the old repeatOnLifecycle will just return and the coroutine will be cleaned up on destroy view and the newly started one will be the only collection
c
Have a look at the Fragment lifecycle

https://miro.medium.com/v2/resize:fit:952/1*UWTA4pWxMjz32Kisy0sjhQ.png

: when you navigate to another Fragment, the current Fragment will enter
onDestroyView
but NOT
onDestroy
. From there, it can re-enter
onViewCreated
on back navigation. Thus, active
repeatOnLifecycle
calls will add up. So still, I believe the documentation is wrong in this point.
r
You are correct in that it would also work with the Fragment's lifecycle scope and registering in onCreate but this will keep listening when there's no active UI being displayed (and potentially try to update a UI which doesn't exist) which is why viewLifecycleOwner is the recommended way
c
Alright, took some time, but now I got it 😉 Thanks for the patience, somehow I all the time missed the
viewLifecycleOwner
part because I had
lifecycleOwner
in front of my eyes… All explanations totally make sense, thank you!