Some questions around `navigation-compose` and Vie...
# compose
b
Some questions around
navigation-compose
and ViewModels. For a time now, we've been able to get a viewmodel scoped to a backstack entry (at first by rolling our own factory, then using a HiltViewModelFactory, and now by using
hiltNavGraphViewModel()
). I presume that means that as long as the backstack entry exists, then the VeiwModel will hang around, and won't be cleared until the backstack entry is popped, right? And if so, you might need to be careful in some cases when launching a coroutine using
viewModelScope.launch
, right? If your are just making a newtork call to fetch a piece of data or something, no big deal. But if it's a longer running operation, then it will not get canceled until the backstackentry is popped from the stack. So, if say you have Composables A, B, and C that are entries in your graph, and you navigate from A to B to C ... if the ViewModel for A launched a coroutine in its
viewModelScope
, it will still be running while the user is looking at C, correct? So if your intention is to launch a coroutine when the user is looking at A and have it get canceled when the user navigates to B, then you really need to use a different mechanism (like say
LaunchedEffect
). Do I have that right?
☝️ 1
i
The
viewModelScope
survives for the entire time the destination is on the back stack and would not be affected by navigating to a new destination, correct. It will be cancelled when you pop the destination off the back stack, also correct.
👍 2
b
Thanks @Ian Lake that's what I thought. Just wanted to make sure I had my use cases straight in my head.
a
not sure we should be using LaunchedEffect for that though, your ViewModel could listen to navigation events and cancel the launch
i
Your ViewModel shouldn't have any references to your composable, etc., so listening for events is not the approach you should use. However, your ViewModel could certainly offer a
suspend
method that you call within a
LaunchedEffect
- that would cancel quite nicely when you navigate
k
Isn’t there any general way to have ViewModel scoped to
Composable
?
i
No, the only scoping available right now is via Navigation Compose. Being able to scope ViewModels to any Composable is being tracked in https://issuetracker.google.com/issues/165642391
🙏 2
b
yeah, the idea in my original post gets at what @Ian Lake is saying. I have a few places where I have to poll a network api every so often, and I only want that polling to run while the user is on the "Screen" composable that uses that data (so I don't waste their battery and data plan to poll for something they aren't even looking at). ... So my ViewModel has a
suspend
method that does the polling, and I call it from a
LaunchedEffect
in the "Screen" composable, and thus it gets canceled when the user navigates to a "child screen", stopping the polling.
i
Yep, there's some more stuff coming out in the next Lifecycle release that will help with handling flow collection in other cases (like hitting the system home button): https://kotlinlang.slack.com/archives/CJLTWPH7S/p1615397085281600?thread_ts=1615395535.277500&cid=CJLTWPH7S
b
yep. good points in the above RE: the coroutine launched via
LaunchedEffect
remains active if the app goes to the background. I work hack around it by using the lifecycleScope of the containing activity, but I'm looking forward to a better solution.
i
Yeah, this new API seems like it will be a good fit for that