I have parent Fragment that contains child fragment. Inside child fragment I have ViewPager with fragments. My question is how can I share ViewModel between parent child and fragments in viewpager and makeing Viewmodel visible only on ParentFragment scope?
what do you mean when you say "visible only on ParentFragment scope"?
According Google's document, there is one way that you can share ViewModel.
Check this document: https://developer.android.com/topic/libraries/architecture/viewmodel#sharing
Shortly, your parent fragment and child fragment will use the same ViewModel. Your parent fragment will call the function of ViewModel to change the data, your child fragment just observer the LiveData of ViewModel.
You can place your sharedViewModel inside your Activity. Then you can access it from every fragment which in attached to this activity with this code:
(requireActivity() as MainActivity).viewModel;
With this approach, you can set data from one fragment and observe data from another fragment. So, you enable communication between two fragments.
Setting data:
viewModel.liveDataObject.value = value
Observing data:
viewModel.liveDataObject.observe(viewLifecycleOwner) {}
Related
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
I have a parent Fragment that has ViewPager which holds another Fragments(child). Some child Fragment can have list. If the user press a back button the list will scroll up if can scroll vertically, another press on back button will move the ViewPager to first item (Fragment).
While I can create an approach like this on child Fragment.
if (adapter.currentList.isNotEmpty() && recyclerView.canScrollVertically(-1))
recyclerView.smoothScrollToPosition(0)
else {
try {
val parentFragment: HomeFragment = parentFragment as HomeFragment
parentFragment.onBackPressed()
} catch (e: Exception) {
FirebaseCrashlytics.getInstance().recordException(e)
}
}
And a public method on parent Fragment like this
fun onBackPressed() {
if (viewPager.currentItem != 0)
viewPager.setCurrentItem(0, true)
else
requireActivity().onBackPressed()
}
I am not sure if this is the best thing to do since I read that Fragments should better not communicate directly with each other, instead communication should be handle by the host Activity or shared ViewModel. But doing so seems an overkill and I do not feel the use of LiveData just for this case.
I would go with the SharedViewModel approach, its kinda built for this. Your child Fragments are effecting the ViewPager that belongs to the ParentFragment. They are effectively part of the same View but the child Fragments don't have access to the View that contains them. So using a SharedViewModel can bridge the gap.
What I would do is make a well defined interface that manipulates the ViewPager and its Adapter as you see fit for your application. That interface should then be accessible through the SharedViewModel.
In the interface you could have a function called navigateToFragment(Class fragmentClass); In this function you would then need to find a fragment via its class inside the Adapter, and then use the ViewPager to go to it. Ie navigateToFragment(HomeFragment.class);
I have 1 activity which contains parent fragment. Inside the parent fragment is 2 child fragments. I want to only create one viewmodel instance and use it in both child fragment.
This is my code in parent fragment:
val factory = ViewModelFactory.getInstance(requireContext())
viewModel = ViewModelProvider(this, factory)[FavoriteViewModel::class.java]
And this one in child fragment:
viewModel = (requireParentFragment() as FavoriteParentFragment).viewModel // force close
It force close without error in logcat.
When i try to move the parent fragment's code to the activity (without changing the code) and change the child fragment's code to:
viewModel = (activity as MainActivity).viewModel // works
It works.
So is it possible to do the first method (that is force closed)? If so, how to do that properly and why i did not get any logcat error.
Instead of trying to access the viewmodel from the parent directly, use the scope of the parent to get a shared viewmodel.
Inside your child fragments, use this code
val factory = ViewModelFactory.getInstance(requireContext())
val viewModel = ViewModelProvider(requireParentFragment(), factory).get(FavoriteViewModel::class.java)
Using the above code, you no longer need to store an instance of the viewmodel in the parent fragment.
Hello i create class that implement BottomSheetDialogFragment with dynamic content. The content is a Fragment. So when initialize the BottomSheet i passing fragment object, and attach it to specific Container ID inside this BottomSheetDialogFragment. Looks like this :
private fun attachContentFragment() {
val transaction = childFragmentManager.beginTransaction()
transaction.apply {
replace(R.id.flContent, state.layoutContent)
commit()
}
}
state.layoutContent is my attached Fragment
I need to dismiss the BottomSheet if every action called in that fragment.
As far as i know, i need to get the object of BottomSheet that hold me(Fragment) and dismiss it.
But how i can get that BottomSheet object?
Thanks
So, technically it is a fragment inside fragment situation. I think there is several solutions here:
Call Activity from your child fragment. BottomSheetDialogFragment will subscribe to Activity for such events and react on them.
Get the instance of a BottomSheetDialogFragment by calling proper FragmentManager (which possible is an Activity one). You can get an instance of a fragment byTag for example.
Or you can call getParentFragment from a child Fragment.
I have Main Activity in that activity there is ReportFragment.
In that ReportFragment there is Viewpager which contains 3 other fragments.
I hav api call data in that 3 fragment.
I want to send data from 3 nested fragment to the Parent fragment i.e. ReportFragment.
which is child of Main Activity.
How to pass data in such scenario ?
You can use EventBus for this case
Also you can use callbacs for it, but it will be callback hell
If your fragment extend from fragment in support library. You can use getParentFragment()
to get instance of ReportFragment. In ReportFragment, you have to implement some method to set data from child fragment.