I'm working with an activity and some fragments. I want to pass data from Fragment A to fragment B after on click element and at the same time navigate from Fragment A to Fragment B.
I read about
ViewModel
to share data between the fragments, but I can not find any information about how to handle the navigation and the use of the ViewModel class in the correct way.
Can anyone provide some example or link aout how to handle this in the correct way to NOT make some "dirty" code or something like that will affect the performance of the app?
I would be very grateful if someones can help with that, thanks.
Related
I am making an app that pulls from a mySQL database. I have a main activity which holds a drawer with a bunch of fragments. If I wanted to make a query and save information in main activity in an array or something, would it be accessible in all of my fragments? I've had trouble trying to send data from fragments, and just read that fragments in the same activity all share the same data. Could someone confirm that if I made an array in mainActivity, that the array would be accessable and mutable by the fragments? (this is my first post, sorry if it's bad)
Why don't you move the array from main activity and create repo which will provide data on request for fragments and main activity. Change in orientation can cause the data in main activity to be wiped out if you are not handling the orientation.
The best way I would recommend is to use view model for the main activity and use that for fragments.
Share data between fragments
Hope it helped. Happy coding :)
I have some trouble with a SingleActivity with a NavHost app in android. There is some text strings from EditText widgets in a fragment that I need to put into a ViewModel, and update the other fragments with the new ViewModel data. I do this from MainActivity in an OnClick method from a floating action button that I is outside the NavHost implementation.
So, I've tried
FragmentManager fm = getSupportFragmentManager();
CreateFragment fragment = (CreateFragment) fm.findFragmentById(R.id.fragment_create);
fragment.saveInputFromTextFields();
But here findFragmentById returns null, and I don't know why.
I have a solution from a question I asked previously, that I use in MainActivity to find the current displayed fragment and calling a method from it;
Fragment navHostFragment = getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
if (navHostFragment instanceof NavHostFragment) {
Fragment visibleFragment = navHostFragment.getChildFragmentManager().getFragments().get(0);
if (visibleFragment instanceof HomeFragment) {
((HomeFragment) visibleFragment).saveInputFromTextFields();
}
}
But this doesn't work after one use, because navHostFragment.getChildFragmentManager().getFragments().get(0); always returns the previous fragment, and changing get(0) to get(1) crashes the app with a IndexOutOfBoundsException.
Maybe I'm going about this the wrong way.
What I really need is a reliable way of setting ViewModel data in one fragment and updating the other fragments with the new data.
I've heard of something called LiveData or DataBinding, do I need to implement something like this? It feels like overkill.
The data I'm working with is one array list in the ViewModel that contains items that fill a recycler view. I use the fragments for creating new items or editing current items, that I just need to get access to somehow. I feel like there is a simpler way, but I don't know how to implement this. Please tell me if you need more information from me.
Thank you for your time.
The Navigation Components are intended to be used primarily for navigating between top level destinations. Therefore a NavHostFragment has a single destination that is currently active at any one time which explains why you can only retrieve the current fragment from its fragment manager.
If you're looking to share data between fragments I would looking into using a ViewModel scoped to your activity so that both your fragments can hold reference. There is some starter documentation here: Share data between fragments. There is also a codelab which will give you a head start into shared view models but also working with LiveData which I would definitely recommend: Shared ViewModel Across Fragments Codelab.
I realized I was going about it the wrong way. The data I needed to update can be updated when the fragments are destroyed and created. So there's really no need for me to tell an instance of the fragment to update the data manually, as that can be handled by android.
Thank you all for your replies.
The problem is quite straightforward. The question is in context of using ViewModels, LiveData and other related Lifecycle aware arch approaches.
I have an Activity with NavDrawer, which switches fragments inside. And also I have a case when two fragments are present at the same time on the screen - this will be the main pain.
One Fragment has a ViewPager with nested Fragments(don't ask why).
The other fragment is just obtaining info from first one when user performs some actions. This is achieved just by sharing activity viewmodel. But the app itself has a lot of business logic and as it goes further the viewmodel goes bigger and bigger.
What I want to ask - not a receipt or rules how to fix this, or maybe how to overcome this by fixing the entire structure of the project. I want to ask for suggestions how can I apply the MVVM approach within android.arch.lifecycle style to mine use-case.
I haven't seen something more complicated then just sharing the Activity ViewModel between Fragments. But common, that's not a cure.
What you can see here - a mess actually. The point is that all are sharing the ActivityViewModel. Connections(aggregation) from FirstFragment mean that ViewPager inside FirstFragment is initiating ChildFragments and they are also working with the same ActivityViewModel(kill me). So as result everyone is working with one shared ViewModel.
My proposal is to add a ViewModel for each Layer. So that Activity/Fragments/ChildFragments have their own ViewModels.
But what appears here - how we should communicate then?
Possible solutions :
Having two ViewModels per one component. One ViewModel will handle/delegate the business logic and another will make the communication. Two viewmodels per component - not so good, yeah?
Having old manner interface(please no!)
Other workarounds - like DB/SharedPrefs/Realm change listeners and Event Buses(I'm too old for this :( ).
Your solution here!
I'll say that all of the above are breaking a lot of design principles, so what should I do?
How should I come out of this mess? Is there any Uncle Bob or another superhero here to help?
P.S. - Well, creating UMLs or other charts isn't mine forte. Sorry for that.
P.P.S. - I'm aware of google samples.
What i would suggest you can do is handle two ViewModel for your entire use case.
Make one ViewModel
Let's say MyActivityViewModel to handle all logic related for activity level. So, if any fragment logic is directly related to your activity then share your ViewModel like below :
ViewModelProviders.of(getActivity()).get(MyActivityViewModel.class); // Like this in fragment.
&
ViewModelProviders.of(this).get(MyActivityViewModel.class); // Like this in activity.
This will share common ViewModel between your activity and fragment.
Another ViewModel would go for FirstFragment in your case if you have to share logic between your ChildFragment :
Here you can share ViewModel let's say FragmentViewModel like below:
ViewModelProviders.of(this).get(FragmentViewModel.class); // Like this in FirstFragment which is having view pager.
&
ViewModelProviders.of(getParentFragment()).get(FragmentViewModel.class); // Like this in View pager fragments, getParentFragment() is First fragment in our case.
Although, we can still use our activity level MyActivityViewModel in our child fragments from FirstFragment like :
ViewModelProviders.of(getActivity()).get(MyActivityViewModel.class);
First there is no harm in having multiple ViewModel's for a single View.
I would think about my ViewModel's like what kind of data is getting and manipulating, and group them in a way, that seems natural.
For your case, if the fragments and the activity's logic is very similar, I think you can go with a single ViewModel, but I would avoid that.
What I would do is break the activity's ViewModel into smaller parts and reuse the proper ViewModel's in my Fragments, so that I wouldn't have a God ViewModel, nor roughly the same code in different ViewModel's.
This is updated version of answer given by Jeel Vankhede. And also Kotlin implementation of the same.
Since ViewModelProviders is deprecated now we have to use ViewModelProvider.
Here is how you do it in Activity:
ViewModelProvider(this).get(MyActivityViewModel::class.java)
Here is how you do in Fragment:
ViewModelProvider(requireActivity()).get(MyActivityViewModel::class.java)
To solve the problem of FirstFragment sharing its view model with its child fragments, you can use this code to access the FirstFragmentViewModel from any of the child fragments:
// in ChildFragment1
val firstFragmentViewModel: FirstFragmentViewModel by viewModels(
{ requireParentFragment() }
)
I have two activities with fragment1 inside activity1 and fragment2 inside activity2
fragment1 and fragment2 extend from Fragment
activity1 and activity2 extend from AppCompatActivity
i want to send String value from fragment1 to fragment2 without getting Null value. I hope you understand the problem.
thanks
Best way to achieve this is using singleton pattern, you can use it for fragment-fragment, fragment-activity communication.
See this answer, it explained with code there and in a very meaningful way. but what i preferred from my experience is you should user EventBus if you want to handle bigger projects with many fragments and larger dependencies, connections and data flows within and between fragments and activities.
The basic communication can be done as per suggested in Developer documentation here
I have read a lot of documents about how to use fragments but I have one more doubt.
I have one activity that controls 3 fragments, now in one of this fragment I call a DialogFragment and following the google's tutorial I defined an interface to the activity for callbacks. All it's works properly but is this the only way to pass data to the fragment that fired the Dialog? I think that it would be more convenient passing data directly to the fragment instead of passing from the activity. is there any method to do this?
Thank you in advance.