We're talking Android here. We've modeled our architecture using Model-View-Presenter approach, and we hit an issue regarding weak references.
Quick Info:
Presenter handles logic, network calls, etc.
Views handles showing data on screen, displaying loading bars, etc.
The Activity/Fragment classes hold a reference to the presenter.
The presenter classes hold a reference to the view classes.
Our view clases are actually interfaces usually implemented by Activity/Fragment. This means a circular dependency between the Activity/Fragment -> presenter and presenter -> view (an Activity/Fragment). For this reason, we made the presenter hold a weak reference to the view (Activity/Fragment).
Today we needed to use 2 views in the same Activity (to display different model-data), so we didn't implements it on the Activity but created 2 anonymous class. This ended up in the presenter losing the view's references (because it's a weak reference).
Now we're evaluating 2 posibilities:
We don't really need the presenters to hold a WeakReference on the View cause this type of circular dependency won't leak memory.
Instead of using anonymous classes, we hold a references on the Activity (so both presenter and activity have a reference to view) just for the sake of it not getting deallocated (which feels smelly).
Which one is it, do we need the presenter to hold the view as a weak reference?
The answer is 1 - you don't need a WeakReference in the presenter in this case. I'm using the same pattern successfully. No memory leaks occur - when the activity gets GCed the presenter goes with it. But there might be other types of problems - if you keep somewhere (for example in AsyncTask) hard reference to the presenter.
As Galya already pointed, you don't need WeakReference for on Presenter because it will be destroyed when Activity destroyed. But if I right understand your problem, you try to "fix" MVP pattern. Maybe a VIPER pattern could help you?
Related
I use Dagger2 for android project
I have 2 scopes: ActivityScope and FragmentScope
I read some sample code and they say that define and use ActivityScope so the object will be destroyed with activity lifecycle. And because Activity and Fragment have different lifecycle, so we should have 2 scopes.
My question is:
Do I need to do something to let the code know that when I use ActivityScope, object should be destroyed with the activity lifecycle? Or the code automatically knows that when I build dagger and inject to Activity like this
((DeezFoodzApplication) getApplication()).getAppComponent().inject(this);
Do I need to do something to let the code know that when I use ActivityScope, object should be destroyed with the activity lifecycle?
No. The garbage collector will take care of it (unless you store it in some static variable).
Dagger doesn't know anything but how to create or inject your objects. It does not care about lifecycle, when or where you inject / create your objects, or how you store your components. There is no magic going on, ther is no service running, or some other hack involved. Components are just some java classes that know how to fill those fields in your Activity with objects. That's all.
If you don't store the component, it will be garbae collected after its use.
If you store the component in a field of your Activity / Fragment, it will be garbage collected with the Activity / Fragment after onDestroy
If you store the component in some static variable or pass it somewhere long-living then it will stay there until you null it or that object gets garbage collected. (Also your Activity / Fragment would probably leak) Avoid storing components in static variables.
It's just a normal object like any other, try not to overthink it. You can always check the generated source code or debug it as well.
I'm using dagger 2 for dependency injection in my android app project.
and the question is how to remove references from component when the activity dies ?
I've read some documents about custom scopes and i've created a custom scope called #ForActivity, so references that have this annotation on them will remove when activity dies, but they don't.
any suggestions on this problem ?
If your component shares the lifecycle of the Activity—that means create the component in onCreate, store it in the Activity itself—it will be garbage collected along with the Activity at the end of the Activities lifetime.
If on the other hand you put a component that references the Activity in some way in a static variable, or some other longer lived object, you will create a memory leak. This is the only thing to keep in mind.
Nothing will be magically "removed" since Dagger just generates POJOs that handle object creation for you. Usually it is enough to just let the GC do its job.
Scopes just group dependencies and define relationships, but in the end your component is just an object that holds more objects. The Garbage Collector will remove it along with the Activity and everything else if you don't create memory leaks as mentioned above.
I recently also gave 2 detailed answers about scopes / activities / scoped objects, where you find more concrete examples on how to work with scopes / activites:
Dagger 2 Scopes, where to place Presenters?
Dagger 2 with MVP, avoid creating extra presenter object on view recreation
Note : This is a question that I asked straight on the LightCycle project github. It's a great tool from SongKick to build a clean MVP architecture over your android app .
There is a thing that I miss thought, I have an activity with many fragments and many fragmentsPresenters.
Sometimes I do computation on my activity presenter and I want to send it to one or many of the fragment presenters (for example my table of content is displayes in the activity menu, and in a fragment that is shown full screen at the beginning).
How to I add a keep a reference of fragment presenters in my activity presenters (maybe it's not how I'm supposed to design it).
Second question. I have MyActivityPresenter that has two children : MyOnlineActivityPresenter and MyOfflineActivityPresenter.
MyActivityPresenter.newPresenter(Network.isNetworkAvailable(contexte), few other args) decides whearas an online or offline presenter is instanciated. So I should do something like :
#LightCycle
PlayerPresenter presenter = PlayerPresenter.get(NetworkUtils.isNetworkAvailable(this));
But I've been told that I should never use context that way as It could be null at the class instanciation moment. Is it indeed a problem ?
also should I pass the few others arguments that I have in the onCreate Bundle ?
And I don't use dependency injection at the moment.
I hope that I'm clear,
thanks again for this very useful lib
This is the answer they gave me
How to I add a keep a reference of fragment presenters in my activity presenters (maybe it's not how I'm supposed to design it).
It is not something in the scope of this library. I can see 2 solutions for you :
inject the same instance
provide an accessor to the presenter from the fragment. (which seems to be better for you).
But I've been told that I should never use context that way as It could be null at the class instantiation moment. Is it indeed a problem ?
also should I pass the few others arguments that I have in the onCreate Bundle ?
Same here.
You can use the app context which should be available and enough in your case
You can init this guy in the constructor because binding happens on create
I am somewhat new to Android, and I am writing an app. I am getting to the point where I am starting to more thoroughly test my code, and therefore, I would like to implement the MVP design strategy since it adds more testable layers to the code. One of the supposed benefits of using MVP that I can not seem to understand is how it helps with running AsyncTasks as they are performed dynamically. Since you want to avoid any Android specific components in your Presenter class, how are you supposed to reference the Activity that utilizes the AsyncTasks? Tutorials about MVP show the Presenter object having methods that take in an Activity as a parameter and return to it; however, if your AsyncTask takes a long time and your Activity has been destroyed through something such as rotation change, how do you return to the proper Activity? I currently store my AsyncTask in a Fragment so that it is saved on Orientation Change. I am having a hard time finding a workaround that implements the MVP practice.
To answer your question, there isn't much you can do to avoid passing Android classes to your Presenter class. But instead of passing the Android object as a parameter, add a method to your View class that returns it (e.g. getActivity()).
That said, I strongly suggest you use a Loader instead of an AsyncTask. Loaders were designed specifically for your use-case. They can also run in the background but their lifecycle is tied to the lifecycle of an Activity or Fragment.
If you switch to Loaders, add a method like getLoaderManager() to your View interface.
If I dont miss-understand your question, your are trying to use retained non-UI fragment for long-runing task, right?
Here is my suggestions in your case:
Make ActivityView interface for your Activity
Using WeakReference<ActivityView> to refer your activity inside your Fragment Presenter (to avoid memory leak issue)
When Activity re-created, try to get your retained fragment and reset your Fragment Presenter's ActivityView. You can look at this Google Example to know how to deal with loading data while configuration changed.
In conclusion, just use WeakReference to avoid memory leak issue, and try to re-set your Presenter'sview when activity is recreated
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.