How to share ViewModel between Fragments with application context? - android

How do I get my Fragments to share the same instance of a ViewModel?
In my ViewModel I need application context so I use "AndroidViewModel" but my MainFragment and DialogFragment don't share the same instace of ViewModel.
How can I achive this?
Here is how I initialized my ViewModels in my MainFragment and DialogFragment:
mViewModel = ViewModelProvider.AndroidViewModelFactory.
getInstance(getActivity().getApplication())
.create(MyViewModel.class);

Related

Shared ViewModel between Fragments with viewPager2

I have a Fragment0 which contains a ViewPager2 that internally may contain 1 or more child Fragments.
I have created a SharedViewModel and defined it in the Parent fragment like so:
val viewModel by viewModels<SharedViewModel>()
I have also added definition for the viewModel in each of the child Fragments.
private val sharedViewModel by viewModels<SharedViewModel>(
ownerProducer = { requireParentFragment() }
)
I use the NavigationControl to navigate to Fragment4 from each of these Child Fragments viz. Fragment1, Fragment2 and Fragment3. My question is, how can I share the same view Model with Fragment4 which is not directly a child of the Fragment0. Can I use the same approach to share viewModel with Fragment4 as well?
Or is there a better way to handle such a usecase?
You can use by viewModels({requireParentFragment()}) only to share viewmodel with parent and child fragment.
It will not work with fragment4.
you can use by activityViewModels().
but it's not good architecture. i suggest you to create separate viewmodel for Fragment4 and share the data with navigation.
find more from here: https://developer.android.com/guide/fragments/communicate

Use viewmodel for a fragment called twice

I have a navigation as follows:
FragmentList -> FragmentDetailA -> FragmentDetailB -> FragmentDetailC
I use a viewModel for the detail FragmentDetailViewModel
private val detailViewModel: DetailViewModel by activityViewModels()
But if I go forward, and then back, the above fragmentDetails are changed. How to have a viewmodel assigned to the fragment without changing the others?
Solution:
First of all, change activityViewModels() for viewModels()
Then, the problem was with setFragmentResultListener. It was called before instantiating the new fragment, then the call was made on Fragment A and not on Fragment B. I decided to pass data between destinations with Bundle objects.
Thanks a lot
With this way that you initialized view model, view model depends on the parent activity you must use this way
private val detailViewModel: DetailViewModel by viewModels()
to your view model instance depends on your fragment instance.
It sounds like you want to link the viewmodel to the fragment.
ViewModelProvider(this,viewModelFactory).get(MyViewModel.class)

Pass arguments to Nav Host Fragment

Lets say I have a fragment flow defined by my nav graph using the Navigation Components and the safe-args plugin.
How do I pass arguments to my nav host fragment?
what for you need to pass to nav host fragment?
you can use shared ViewModel to pass some data from one fragment to another.
for example if you need to share some data between fragments that are in the same navigation graph you can use trap scope ViewModel otherwise activity scope ViewModel.
activity scope (val viewModel: YourViewModel by activityViewModels())
or
navigation graph scope (val viewModel: YourViewModel by navGraphViewModels(R.id.desired_graph))

How to have separate instance of ViewModel in each Fragment and have shared data as well between Viewmodels

I am working on Android TV app
And I have a Fragment(main Fragment) and inside fragment have side menu, each menu Item creates new fragment(menu Fragment).
I have Viewmodel and in ViewModel I have config livedata which I am loading when I main Fragment is created.
And Menu Fragment's data is based on data I am getting from API calls and from config data
I have created single instance of viewmodel with the activity lifecycle.
But the problem is when I am navigating from one fragment to another for example from 1-2 fragment and as 1 fragment has already loaded data the livedata is not empty and navigating to 2nd fragment before fetching the second fragment data it observes/displays the livedata from first fragment and then it's own after it fetches it's data
I think each fragment should have it's own instance ,but I also need data which should be shared (the config) between the each instance of viewmodel ?
How can I make this?
private val viewModel: HomeViewModel by lazyViewModelActivityScope()
viewModel.fetch()
viewModel.configData.observe(viewLifecycleOwner, Observer { it ->
loadData(it)
})
it is inside MenuFragment
private val viewModel: HomeViewModel by lazyViewModelActivityScope()
viewModel.fetchMenuPage(menuItem)
viewModel.carouselsWithAssetsData.observe(viewLifecycleOwner, Observer { carouselWithAssets ->
carouselWithAssets.forEach { carouselWithAsset ->
mRowsAdapter.add(createCardRow(carouselWithAsset))
}
})
I got the answer of my question and I want to share it with others
I think generally this is something you'd manage with DI (injecting the same config into both ViewModels)
Or each Fragment would need to pass the activity ViewModel's data to the Fragment's ViewModel. Or you could have a global LiveData that manages itself (loading data in onActive()) and skip the activity ViewModel entirely

Retaining ViewModel in fragments

I'm collaborating with ViewModel and fragments, and would like to retain my ViewModel for my fragment on rotation change. When passing my Fragment into ViewModelProviders.of() it does not get retained, but when I pass the Activity that the fragment belongs to, it is retained. So is passing the activity how it is supposed to be used?
Calling ViewModelProviders.of(this) in Fragment won't retain my ViewModel. Is that expected behavior?
class MainFragment : Fragment() {
private lateinit var viewModel: MainViewModel
fun OnXXXXXXXXX {
// This _will NOT_ retain ViewModel
viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)
// This _will_ retain ViewModel
viewModel = ViewModelProviders.of(activity).get(MainViewModel::class.java)
}
}
Yes, its expected behaviour, Look at this content
Fragments can share a ViewModel using their activity scope to handle this communication
If you want to share same ViewModel, use same context. For Example, multiple fragments on same activity:
ViewModelProviders.of(activity)

Categories

Resources