remove references from memory - android

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

Related

Dagger2 using Scope

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.

Dagger 2 Scopes, where to place Presenters?

what would it be the best practice about placing Presenters in a Scope?
Could we have Presenters on #Singleton or #AppScope without any problem?
Should they be placed in an #ActivityScope in order to destroy them each time the activity is destroyed?
what would it be the best practice about placing Presenters in a Scope?
Usually a presenter should be in some scope. Not placing it in any scope will lead to problems, as every time you request a presenter it would create a new one.
Which scope you choose mostly depends on your programming style, but the most common would probably be #PerActivity, as a scope that follows the lifecycle of the Activity. (the same way you can use something like #PerFragment with Fragments and their lifecycle)
Could we have Presenters on #Singleton or #AppScope without any problem?
Yes and no. Longer living objects referencing shorter lived ones (e.g. a #Singleton object that references an activity-lifecycled one) usually is not a good practice that might lead to memory leaks.
You can avoid these issues by properly adding / removing your shorter lived objects (e.g. add in onCreate, remove in onDestroy) or using WeakReference.
Some programmers will keep their presenters as #Singleton or in some similar fashion and swap views, but again this depends on how you prefer your code. It will work, but you must make sure what objects you reference and to clean up afterwards.
Should they be placed in an #ActivityScope in order to destroy them each time the activity is destroyed?
This is by far the easiest option, since you have no problem referencing the Activity or anything else that depends on it. You most likely won't have to worry about memory leaks or other issues this way.
In the end its your code and you have to do what works best for you.

Do I need to use a WeakReference for circular dependency?

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?

Can Dagger 2 have scopes shorter than an Activity life?

I've been looking at Custom Scopes in Dagger 2 (this and this are the ones i'm trying to base my code in), and there's one thing that i still can't seem to understand, i see that you can create a component with a custom scope and then all the provides form the modules contained by that component will be either the same scope as the component (singleton in the component) or un-scoped which will return new instances every time you get one.
But, the thing i still don't get is, if you have a User scope, and then you have some modules tied to that scope, let say that your network component is tied to it, so that the network calls use the current user information, if you sign-out the user (or sign in the user) mid Activity life cycle, will it change the object references that you currently have marked as #Inject? or whatever instance you got when you called .inject(this) in the activity onCreate method?
Or you should call inject one more time in order to get the references mapped again?
Any help on this matter is highly appreciated :)
tl;dr You have to manage everything yourself. There is no refresh, you have to recreate or at least reload parts of your activity.
Scopes provide some compile time information and help you to keep your code "readable". To actually swap components, this you will have to do yourself. And yes, you have to build your design around this, that depending components get recreated accordingly.
If the user logs in / out you will have to create a new UserModule and component referencing the new user, supplying logged in / out objects. This is the new component you need to reference for all future components depending on it.
#Inject annotated fields will not refresh automatically, albeit you can just inject a second time to the same fields, the objects will just be overwritten.
In the second link you provided they actually do implement some sort of swapping the user information. This is done by keeping the UserComponent in the application class.

Module per Fragment / Activity in Dagger

I'm wondering if it is better to have a Module per Activity than a Module per Fragment? In one of my projects, I have an architecture to have a Module per Fragment because I use Activity just to hold and swap Fragments and nothing more. I only create Presenters and Interactors when I need them, i.e. when Fragment.onCreate() is being called.
But I can see guys are creating Module per Activity in their examples. While the idea to have an independent Module for Activity sounds perfectly reasonable as for me from a modularity perspective, but I still believe creating and keeping all objects (Presenters, Interactors) before you actually need them is not a best idea. You can't also release resources when you don't need them, which you could easily do for Module per Fragment when you just release a scoped graph in Fragment.onDestroy() event.
The examples assume you're working with several activities, each with their own clear purpose and scope. There exists a scope A for the application wide dependencies, and scopes B, C and D for each of the Activity dependencies.
You're basically adding an extra layer to the hierarchy: Application-Activity-Fragment. In that case, since you're working with a single Activity, scope A is roughly the scope for the application and activity dependencies, and B, C and D become Fragment scopes.
So yes, it makes sense to create a module for each Fragment.

Categories

Resources