So typically init {} in viewmodel to "kick off" wo...
# compose-android
c
So typically init {} in viewmodel to "kick off" work is seen as an anti pattern. What other options are there for something to get kicked off once while the destination is on the nav-compose backstack?
LauncedEffect(myViewModel)?
Something else?
i
Kicking off work in init specifically with
Dispatchers.Main.immediate
is actually the real problem child, since it will start (and potentially complete work) before the creation of the object completes and the composition it is associated with is actually valid. Using any other dispatcher that always dispatches removes that particular problem
👀 1
But generally if your data flows are all cold flows (or flows that use stateIn with while subscribed), you'll already have the best behavior possible - only starting the collection when the UI is valid and when it starts collecting from your ViewModel
👀 1
m
in case kick off work is all cold flows then I use, as Ian said,
stateIn
with
WhileSubscribed
. if I need to do something else I create my own
fun init() {…}
that I explicitly call from a composable using:
Copy code
rememberSaveable { viewModel.init(); 1 }
I don’t know if there is a better way to do this but this works
☝🏻 1
☝️ 1
👀 1
s
Also when doing things on
init
you gotta make sure that you do in fact want it to only be done on init. More or less every time I've seen that pattern that was not the case, but they did want that work to be done when the screen came back (from popping other screens in the backstack) into view and the VM at that point was already there, it didn't just initialize. So cold flows that rely on a listener being there + collectAsStateWithLifefycle is more or less always what you wanna do instead, exactly as Ian explained.
👆 1
c
More or less every time I've seen that pattern that was not the case, but they did want that work to be done when the screen came back (from popping other screens in the backstack)
interesting. in my case I feel like i end up seeing this a lot in the opposite direction. i want the work only done once, and i definitely do not want the work to be done again because i came back to the screen. great points all around though. Maybe it I truly want something done once, I should just put it in the rememberSaveable (even though that kinda feels ugly and feels like my LaunchedEffect trick too) lol
s
Depends on what "the thing" is. If it's fetching the data for the screen then you definitely want to re fetch, otherwise you will have stale info showing. What is your use case where you definitely want it done once?
c
typically fetching data (either local or network). local is typically setting up listeners to flows for something like sqldelight. but with network calls we haven't necessarily wanted to refresh data just because you come back to that screen.
i
If anything, data changes on the remote side should be loaded independently, say in response to a push notification triggering a WorkManager job, which would update your repository which would "refresh" your screen automatically
103 Views