I am working with Fragments in Android. I have two identical fragments FragA and FragB. Since they are identical: I need a method that says if I am on FragA and a textView in FragA changed or updates the same textView should change/update in FragB. Can anyone help me with creating a method that takes data from FragA changed about a particular View and passes it to FragB to update its View.
I have tried using interfaces and ViewModel for communicating with fragments, but I can't seem to figure out how to update two identical fragments when let's say one of them changes.
This is actually an easily approachable problem these days. With a ViewModel we can achieve this easily.
We can make a ViewModel where our MutableLiveData can live.
Our two (or more) fragments can observe the LiveData events and both update at the same time.
I could post some code but I really think this CodeLabs is exactly what you are looking for and can get you up to speed in just a few minutes.
Android Lifecycle Aware Components Codelab
You can easily do this with an external and awesome library, https://github.com/greenrobot/EventBus . This is a hidden gem for easy fragment to fragment communication in android. The docs are pretty self explanatory.
Please note: if you are using eventbus please remember to register eventbus only in the fragments OR classes you will be using it in, you do not have register an eventbus even in the class from where you are posting the event, else it will be giving you a compile time error. Also DO Not forget to unregister the eventbus using EventBus.getDefault().unRegister(this); or EventBus.getDefault().unregister(context);
in order to prevent memory leaks
Related
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 an Activity that hosts multiple fragments that define each step in a registration flow for a user. The flow is complex and the next step is defined by user actions in the previous steps.
The flow is like below:
MainActivity | Fragment1 --> Fragment2 --> Fragment3 --> Fragment4
\
--> Fragment5 --> Fragment6
Following MVP, I have View & Presenter for each Fragment involved. The concern I have is how to communicate between the Fragment and the Activity in an MVP way. The result of each Fragment needs to be available to the Activity to decide what Fragment needs to be shown next.
One of the approaches I have thought of is to have a listener defined for each fragment which is implemented by the Activity. I somehow find this a little ugly because in the end the Activity needs to implement 6 of these and doesn't look scalable.
What would be a better approach?
In my project I use the fact that each Fragment has access to the parent Activity. My solution is:
As you have mentioned that you want to communicate with fragments using MVP.According to me I found 2 solutions.
Solution 1:
Callbacks using interfaces, rather creating one interface & bombarding lot of methods that need to be perform on activity/fragment. Try to create more than one interfaces & add methods according to your functionality & implement those according to your use.
Solution 2:
Event Buses is the other solution using MVP, where your view observes the bus & picks up event. Following points to take care when dealing with event buses:
a. If you are using publishing or subscribers within an Activity of Fragment they should be registered and unregistered with their lifecycle. Otherwise, it's likely you will encounter memory leaks or dangling references that can cause your app to crash.
b. Be wary about publishing events between Fragments. Events cannot be published or received when a Fragment is not running. If you have a Fragment publishing a message to another Fragment that isn't currently executing and then swap one for the other, it's likely the event will not be processed correctly. The EventBus library has a way to replay this event, but the Otto framework does not.
For Event Buses you can refer two libraries:
- GreenBot : https://github.com/greenrobot/EventBus
- Otto : http://www.vogella.com/tutorials/JavaLibrary-EventBusOtto/article.html
Conclusion
If you are dealing with small operations on Activity/Fragments then dealing with interfaces is better option. Event Buses increases your app performance, also dependencies for larger scopes you can go for event buses.
Firstly, I know that with Model View Presenter there are different implementations, and in my mind as long as you have the layers of abstraction clearly defined and doing their appointed roles then how you implement this pattern is open to interpretation. I have been implementing this pattern in quite a few apps where there was just one Activity. I've now started a new project that has multiple Activities and attached Fragments, including nested fragments (ViewPager).
I'm now trying to translate the MVP to this project and I've hit a concept wall and would like some guidance and insights.
So far I've created the above structure and started to do a 1 : 1 relationship with View & Presenter (regardless of Activity or Fragment). I feel that this is OK, however if for example I sent a request to do something from an Activity View to its Presenter, which returns a result to the Activity View how would I go about propagating the result i.e. update all the other Activities/Fragments that are currently not in a Paused() or Stop() state. I feel like in this case there should be a central Presenter that updates all necessary Activity and Fragment Views, but I'm not sure how to go about doing this.
Currently when each Activity and Fragment is created it creates a new instance of a Presenter class, passing in itself as a reference (the Activities and Fragments implement their own interfaces), which the presenter stores as a WeakReference and can invoke the relevant interface methods when returning a result.
According to the docs whenever Fragments want to communicate with one another and the attached Activity you should use a callback interface. With this in mind should I have one callback interface that the Activity implements and the Fragments callback to whenever they request something, so in essence only the Activity would have a Presenter and Model layer that the Fragments have to callback to in order to make various requests?
Sorry if this sounds a bit muddled, hopefully this is clear enough to understand what I want to achieve, and if I’m thinking along the right lines... or totally off the mark!
I think this is okay to have a presenter inside activity. Basically activity is like a controller, it should know about the presenter.
It would be wrong to put a presenter inside a fragment if activity or other fragment needs it too. You can put a presenter inside a fragment only if this presenter is designed specifically for fragment.
which the presenter stores as a WeakReference and can invoke the relevant interface methods when returning a result
Why do you need a WeakReference here? If you have 1:1 relationship then I assume your presenter does not have it's own lifecycle, meaning that it's lifecycle depends on either activity or fragment. There is no risk of having memory leaks because it's not a singleton, right? It should be safe to have a strong reference.
I'm not sure if I answered your question because it looks a bit broad to me. My point is that, fragments are just separated "parts" of activity and you should treat them as parts. If presenter belongs to this part only, then it should be inside. Otherwise it should be in activity. You are right about using an interface to access activity, this is a well-known design approach which Google uses in their examples.
Nope, no interface anymore. You either use RxJava Observables to update all the views as described here or some kind of Bus(Otto-deprecated or EventBus). And you will like it because they make interacting too easy.
I am creating my app with using fragments. I have something like main activity, it has FrameLayout as root layout to hold fragments.
After much thought I have decided to separate my application logic in several parts, for example : MainActivity is responsible for app basic navigation (MainPageFragment, CategoryListFragment, ProductListFragment, ProductDescriptionFragment), AuthActivity is responsible for autherization, registration (SignInFragment, RegistrationFragment, RecoverPasswordFragment).
A little about my app. If you have recommendation or don't agree with app structure, I would be grateful for any critics.
What is the problem, as you can see my MainActivity has many responsibilities. There are four Fragments now but it can be more in the future.
Lets consider next situation. In my MainActivity I have MainPageFragment and this fragment in turn of course has some views. And on click event I need to change fragment, for instance from MainPageFragment to the CategoryListFragment. In this case I have several ways to handle clicks or other events from framgents.
The most common way is to have activity implements callback interface defined in fragment class as nested class inteface. This approach is quite good and easy to use. But what if my host activity has to handle multiple callbacks from fragments, to say more, there can be more than one callback from single fragment, class(activity) declaration starts growing, class body too. What are another possible approaches to solve this problem.
You can handle all clicks, events directly inside fragment (start activity, replace framgent......) you can do this painless, but for me personally callback approach looks better, but maybe there is nothing bad, and I can use this approach.
Use one or several interfaces for getting information from fragments. For example create class CallbackEvent for holding such info as framgentId, eventType .... Using this approach we can reduce interfaces and methods, but Activity class body can become larger in first approach.
Use something like EventBus pattern to communicate between app components via third party service.
Of course there are some other ways to do this, but I have described most popular.
Please suggest, or just explain how to do you solve this problem in your apps, what approach is better, how to built this communication easy to maintain.
I am grateful for any advice,critics in advance.
If your app becomes more complex using the callback pattern will get messy, especially if fragments need to communicate with fragments. I'd only use that pattern for apps with low complexity (activity, one or two fragments).
Clicks, events etc. should be handled inside a fragment if whatever happens stays within the fragment. Don't replace a fragment from within the fragment, that's the Activity's responsibility. It might look easier to just do a getActivity().someMethod in the fragment but this leads to hard to maintain code. You might understand now what it's doing but will struggle in half a year.
This approach looks messy to me too (similar to 1.)
That's the one I'd recommend. I'm using EventBus (https://github.com/greenrobot/EventBus) but there are alternative implementations like Otto (https://github.com/square/otto) and I've never looked back to the times when I used the callback pattern. Using an EventBus decouples the communication between the different components and your code becomes much simpler and leaner. However you need to be careful with that approach since there are some pitfalls. One is that it gets much easier to communicate from any component to any other component which could lead to even messier code than the listener/observer pattern. Another one is that events are asynchronous compared to synchronous listener calls so you need to make sure you're only receiving the "right" events at the right moment in the component's lifecycle. The main advantages of an EventBus approach are IMO:
A message is always an object forcing the developer to code object oriented compared to the more functional listener method calls
It decouples the different components. Publisher and subscribers don't have to know about each other. Decoupling the components will make your code much leaner and easier to read (and maintain).
It can be used by arbitrary components. E.g. I replaced all LocalBroadcastManager calls by EventBus messages (EventBus is MUCH faster that using a LocalBroadcastManager). Being able to communicate between arbitrary components is especially convenient if the components can't access each other directly (like a Dialog and a Preference object)
I have two rules of Fragment - Activity separation.
One is logic. Anything that deals with View (layout expansion, display, listeners, etc) should go inside a Fragment. Important background processes (http requests, file reading, image processing, etc) should go inside Activity. Part of the reason is explained in my second point:
Lifecycle. Activity's lifecycle outlasts Fragment's. Fragment is also fragile it doesn't even retain its views. And this is the reason Fragment should be decoupled from Activity. Listeners and callbacks are tight coupling and they are the cause of countless null pointer exceptions when some process tries to update a View of a Fragment that has called its onDestroyView. Having said this I'd suggest Publisher - Subscriber pattern like Event Bus where you can plan a message delivery in which it gets digested only when a publisher (which in this case corresponds to Fragment's view) is available.
The numerous click listeners you have are related to how you design your UI. Moving code around doesn't really help much, unless you trim down your layouts.
I have faced with the problem. My Activity is fragment container, so to communicate between activity and fragments I used common Callback approach. In this case my activity has to implement tons of callback interfaces depending on fragment count.
I don't like to hardcode and unreadable code. In my case my class declaration can take several lines to list all interfaces.
I am trying to get rid of this.
There is another approach is to use EventBus pattern.
In activity
EventBus.getDefault().register(this);
In fragment
EventBus.getDetault().post(new MyEvent(description));
And handle several event types in activity.
Maybe there will be better to use EventBus here instead default Callback approach ??
Or maybe there is my fault that my activity is holding a lot of fragments (God Object) and it is better to use activities instead Fragment ?
Please suggest which approach is better ?
For simple one Activity to one Fragment hierarchy, callback is simplest decision to go. But think about Activity containing a Fragment, and the Fragment contains swipe-able ViewPager, and each tab of ViewPager has Fragments A,B,C.
The Fragment A,B,C will go to long journey to send event to mother Activity, and it can be lost interface connectivity between Activity and children when they are restored during crazy complex Android Activity-Fragment lifecycle dances. In this case, eventbus like otto can be a good choice.
The drawback of event bus approach is, it is hard to maintain where the event is come from. So, keeping a few sender is recommended.
Your interface approach is awesome, just keep up with them, and maybe try and slice/make your interface static and add all the little little voids and return methods to that interface so you can just implement one and call the functions.
EventBus? how about LocalBroadcastReceiver ? its a matter of preference and which one you feel will suit you better, after all if you handle 10,000 request and hate having 100 interfaces, you will end up using 1 and nesting 99.
& just forgot, it is better to hold alot Fragment instead of Activity because at the end of the day the Activity lifecycle is pretty hard to maintain second of all you can not really control Activityies well all as compared to Fragments and Fragment is a good slave, serves you better
hope its valuable