not necessarily kotlin specific, but let's give it...
# android
s
not necessarily kotlin specific, but let's give it a try: I'm using Jetpack navigation to navigate between two fragments. One is a list of things, the other one shows a specific thing. On the list I'm getting an
Observable<[Thing]>
, and I'd really like to pass a
Observable<Thing>
to the second fragment. However, I cannot figure out how. I have the list observable in the first fragment's view model and my intuition is that when making the transition, there should be a way to prepare the view model for the second fragment and then it can find it via
ViewModelProvider
. Can't figure out how to do it, though. Maybe there's a totally different way. Any clues?
a
Your "intuition" is correct you can share a view model . If using navigation you can share viewmodel for a part of your graph out of the box. https://stackoverflow.com/questions/55137338/android-navigation-component-with-shared-view-models The key is this should be the same instance of the view model. You can always pass your data as arguments too
s
thanks. is it possible, though, to be a bit more fine grained? Fragment A has View Model A, it knows it opens Fragment B and has the data Fragment B needs. I'd rather have View Model B (so fragment B is reusable), but I'd like fragment A to prepare it before it opens Fragment B. As far as I can tell it's possible if I put fragment B in a separate Nav Graph, but not sure if I can do it when they are in the same graph
a
One fragment can have multiple view models. Fragment B can have two instances view model A and view model B but of you want to avoid references to viewmodel A from fragment B whatsoever then you have to pass the data to fragment B to be used 🤷
s
sure, but the data is an Observable here and I cannot pass it through args (since it's not serializable)
I guess the fundamental question is how do I pass non-serializable data to a fragment
a
You can pass the data itself what you need to display (not the observable instance)
But if you need to persist user's modifications of that data the better way is to share some observable instance which can be inside a view model
Your observable holds data so pass that data and not the observable itself
s
I kinda want to pass the observable as the new fragment can make a modification and I'd like to get the new value through the observable, not specifically handle it in the fragment
a
Then you have to provide access to that observable from fragment a and fragment b, so that observable can be in a shared viewmodel (I think this is a standard way now) or it can be global/static in a companion object for example (which we had to do once as there was a complicated set up) but the latter doesn't seem clean to me and smells a bit
s
yeah, so ideally, instead of sharing a view model, I'd like to setup a view model in fragment A to be used in fragment B. That way fragment B doesn't know about the view model of fragment A and can be invoked through multiple paths
a
I see what you mean, you can do it in reverse , give whichever fragment is invoking fragment b access to view model b to set the data before navigating to fragment b
So if fragment c navigates to fragment b , fragment c will know of viewmodel b but fragment b will not care if it is fragment a or c start destination
s
sure. I tried that, but then
onCleared
doesn't get called
a
For that I would create viewmodel b as a Singleton if you are using dagger for example it is pretty easy
s
not using dagger. Unsure I want to use dagger
a
Yeah, I have faced a similar issue but the solution was to have a custom method in view model purgeData or something that will be called on Fragment b onViewDesroyed for example to reset
s
got it
just handle clearing in fragment B?
a
Yeap, tie it to fragment b lifecycle and clear data in viewmodel
s
I was trying to set up a viewmodelstore in some way before the transition, but failed
a
I am not sure it is possible
s
technically if I put fragment B in a new graph, I can obtain it after I call
navigate
and tweak it
but then I need to wrap it in a new graph 😕
anyway, that was very useful. Thank you!
a
Why do you think it is necessary for it to be in a new graph?
You should be able to get its instance in the same graph I would expect
s
yeah, but then
onCleared
doesn't get called since the view model store is shared for the whole graph. If I put it in a new graph, the new graph can have its own view model store, and it gets cleared automatically when it gets popped
otherwise, yeah, I can get it in the same graph, but then it needs the manual clearing as you suggested, which I guess will do
a
Ok, I see what you mean , that situation smells a bit , I would report a bug and see what Google replies
s
thanks 🙂
z
What a long discussion and no mention of scoping
ViewModel
to a shared
NavGraph
, why is that?
the ViewModelStore should be managed by the NavGraph as you navigate back Navigation should kill it, if it doesn't then Navigation is bugged