Looking for an idiomatic way to perform some long ...
# android
m
Looking for an idiomatic way to perform some long running background Job in the viewmodel such that the work will be paused when the user navigates forward, resumed when the user navigates back to the fragment, and cancelled when the user navigates back from that fragment. I know the viewLifecycleOwner is probably useful for that and that the viewmodel can implement
LifecycleObserver
to observe the fragment lifecycle, but what I’m struggling with is a mechanism of how best to use these callbacks to control the work.
i
This seems like a pretty non-idiomatic requirement. Can you explain your use case?
m
I have a
RecyclerView
which shows a list of items initially in some plain state. In the background the viewmodel grabs more information about each item and periodically updates (via MutableStateFlow) that list (as it makes progress). Note - it is important the user can scroll to the end of the list without waiting for all the items to be fully processed.
i
Sounds like the exact use case for Paging with placeholders, where you can scroll through the whole list but data for each "page" of data is asynchronously loaded in
m
Are the placeholders configurable? i.e. different layout/content per item?
i
Paging 3 supports multiple ViewHolder types and you can do whatever you want in
onBindViewHolder
when the item is null (i.e., when the item isn't loaded)
m
Hmm, so I can’t derive any item data from a null item. What I need is for a non-null item to have two possible states: plain and processed. That cannot be achieved with null items, unfortunately.
I should probably use the term “basic” instead of “plain” to be more clear
I can use
LifecycleCoroutineScope.launchWhenStarted()
which uses a (internal)
PausingDispatcher
to accomplish what I need.
k
With lifecycle you can react to Fragment changes, so you can send some kind of pause event to viewmodel, but coroutines can not be paused. maybe using a queue and looper
m
@kristianconk yes although the concept of a pausing dispatcher does exist internally and is used by, for example,
launchWhenStarted()
. I found the
launchWhenStarted()
approach helpful for when moving forward from the fragment and then back to it, but not for configuration changes because I guess a new
lifecycleCoroutineScope
comes into play. So I ended up using the
ViewModel
as a
LifecycleObserver
approach. I used the callbacks to maintain a
MutableStateFlow
and then used that to help control the long running task.