How can I get the same instance of my ViewModel ac...
# compose
n
How can I get the same instance of my ViewModel across navigation? 🤔 I mean, I have a screen
A
which instantiate my ViewModel using
viewModel()
function. I want to get the same instance of my ViewModel in screen
B
after call
navController.navigate("B")
i
nested graph?
n
Not actually… ScreenA calls ScreenB
i
If I'm understanding what you're saying, it sounds like this previous conversation: https://kotlinlang.slack.com/archives/CJLTWPH7S/p1621084875089500?thread_ts=1621077994.082300&cid=CJLTWPH7S
n
Thanks @Ian Lake, but I don’t wanna use Hilt right now… Is there another way?
i
The concept of using
previousBackStackEntry
applies to any kind of ViewModel
I think the piece that we're missing is that there's no
viewModel()
method that takes a
ViewModelStoreOwner
(i.e., that
previousBackStackEntry
object)? It just always uses the
LocalViewModelStoreOwner.current
That sounds like a valid API we should add if you'd like to file an issue against AndroidX -> Lifecycle and include a link here
viewModel()
is just a one liner around
ViewModelProvider(owner, factory).get()
n
Great! I’ll do that… 👍 Definitely it’s better than pass the vm as “navigation param”
i
Note that when your process is killed and recreated, you'll still be on screen
B
and that ViewModel won't exist anymore
So your first access to it in screen B will be to create a brand new instance
n
That’s important… Using Hilt will avoid that?
i
Which is why the guide for returning a result uses the
SavedStateHandle
of the previous destination (which only contains information that survives process death and recreation): https://developer.android.com/guide/navigation/navigation-programmatic#returning_a_result
No, all ViewModels get destroyed when you go through process death and recreation
Just something to be aware of if you're assuming some data / state exists from Screen
A
. Of course, your own custom ViewModel could have its own
SavedStateHandle
- that same
SavedStateHandle
will be redelivered to the new instance upon recreation
The Saved State integration with ViewModel docs talk about that general pattern: https://developer.android.com/topic/libraries/architecture/viewmodel-savedstate
n
I see… but I guess this is different problem… If I implement the
SavedStateHandle
correctly in my ViewModel both screen will restore the data correctly, right?
If I understand correctly, currently, to share a view model across navigation, I should use
previousBackStackEntry
. Lifecycle API nor Hilt can solve this right now…
i
If all of the state you need in the ViewModel associated with Screen
A
can be saved into a
SavedStateHandle
it owns, then yep, it'll be restored properly whether it gets created from Screen
B
or Screen
A
The 'Don't keep activities' developer option is really handy for testing this case - it means that you can simulate process death just by hitting the home button, then relaunching your app from recents
n
how can I pass the ViewModel to the
previousBackStackEntry
? It’s a
Bundle
🤔
i
So if on screen
A
, you did
val vm: MyViewModel = viewModel()
, screen
B
could do
val vm: MyViewModel = ViewModelProvider(navController.previousBackStackEntry).get()
to get that same ViewModel instance
n
It’s not working… 😕 Is this what you asked me to open an issue?
i
What 'isn't working'
n
ViewModelProvider
expects a
ViewModelStoreOwner
not a
NavBackstackEntry
😕
i
NavBackStackEntry
implements
ViewModelStoreOwner
n
You’re right… but it’s not working… let me check…
i
Looks like you're missing a
!!
- the nullability is the problem, not the class
🤦‍♂️ 1
n
It works! thanks @Ian Lake I’ll open the issue and post the link here 😉
here it is: 😉 https://issuetracker.google.com/issues/188693123 not sure if it’s clear enough though…
i
Close enough for me to work with it 🙂
🤩 1
I suspect it would end up to be something like
val vm: MyViewModel = viewModel(navController.previousBackStackEntry!!)
🥲 1
n
Maybe some
key
param, or
sharedViewModel()
, or some scope…
i
You have a scope - that's what a
ViewModelStoreOwner
is
n
ok… I’d guess that would be nice to have
viewModel<T>()
will create a new instance and
sharedViewModel<T>()
will check if there’s an instance of the ViewModel, return it.
i
Well,
viewModel()
already avoids creating a new ViewModel if the
LocalViewModelStoreOwner
has already created that ViewModel - it just returns the previously existing instance
And outside of the
LocalViewModelStoreOwner
, there's many, many possible owners that might be appropriate