My Android app has multiple activities. The MainActivity constructs a Dagger2 component in its onCreate() method and assigns it to a static variable so any class can call the static method MainActivity.getDaggerComponent() to then inject itself with dependencies.
The problem I'm discovering is that when I start up my VideoPlayerActivity, the MainActivity object sometimes gets its onPause() invoked. If this happens, the static component variable gets set to null. At a later point, VideoPlayerActivity needs to inject its dependencies, but there is no component so things blow up.
How does one ensure that a Dagger2 component is available at all times for all activities?
Initialize Dagger component in Application class or just statically. It might be that you're doing a very wrong thing trying to use dependencies of one Activity in another Activity. This might create memory leaks and in particular sounds like a design problem. What if your first Activity was already destroyed? Who will free up the Dagger instance? Why graph belongs to first Activity and not to the second one? What if user will enter your app from the second Activity - then first one won't be even initialized. And so on, and so on.
If you still need Activity instance, then you should use Activity specific component within the Activity and move everything else in global (Application wide) component.
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've read a lot of posts and tutorials about dagger 2:
http://frogermcs.github.io/dependency-injection-with-dagger-2-custom-scopes/
https://github.com/codepath/android_guides/wiki/Dependency-Injection-with-Dagger-2
http://fernandocejas.com/2015/04/11/tasting-dagger-2-on-android/
https://github.com/konmik/konmik.github.io/wiki/Snorkeling-with-Dagger-2
What determines the lifecycle of a component (object graph) in Dagger 2?
etc.
But I am still confused about the lifecycle of a component, and how it relates to module and scope. I want to make sure I don't create multiple instances of an object when I only want a Singleton. Hope someone can shed some light on these:
What's the lifecycle of a component that's built in the application class?
What's the lifecycle of a component that's built in the Activity or Fragment class?
If I want a singleton instance from a component, do I must annotate the component with #Singleton or a custom made scope and build that component in the application class?
If I build a component in the application class, does that mean all the object instances available through this component will be a singleton instance throughout the app until the app is killed or restarted?
I have a component with a custom scope let's say #ActivityScope, and I build that component in an Activity, will the object instances injected through this component be destroyed automatically after this activity's onDestroy() is called?
Again I have a component with a custom scope let's say #ActivityScope, and I build this component in ActivityA and ActivityB, will ActivityA and ActivityB share the same object instances from this component or they will have their own instances of the same object?
How I understand it:
And keep in mind two things (when I first read 1) it it made everything cleaner to me):
1)Components live as long as you want it to or as long as class that created component wasn't destroyed (like android activity or fragment)
2)If you don't annotate you provide methods with annotation (must be the same as component annotation) new objects will be created every time you request for them
What's the lifecycle of a component that's built in the application class?
Component built in application class lives as long as you want. I mean you can create it at any time and remove it at any time as long as you create it in class that extends android Application class (this way component object will live as long as your Android App is running) in contrast to component that's built in activity class - it will live as long as activity is alive so it may be destroyed for example on orientation change.
Keep in mind that if for some reason you didn't create your ApplicationComponent in onCreate() method of Application class (for example you created it later when something happened) it can be destroyed (nulled) when Android OS is low on memory and user closed your app, and then when user comes back to your app (to last visible activity) when it has been killed earlier and you ask your app component to do something then check if it's not null
What's the lifecycle of a component that's built in the Activity or
Fragment class?
I partially answered it in above answer. If you create your component inside Fragment/Activity it lives as long as you want or as long as activity or fragment is not destroyed due to orientation change or low memory
If I want a singleton instance from a component, do I must annotate
the component with #Singleton or a custom made scope and build that
component in the application class?
It depends where you want to use this singleton. If you want singleton in single activity you may create for example #ActivityScope annotation and annotate provide methods and ActivityComponent with this annotation, then you create your ActivityComponent inside onCreate() Activity method and you have a singleton as long as your activity lives (it may be helpfull if you plan to have a singleton shared between different fragments from same activity).
If you want singleton between different acctivities/fragment in app the best way to do that would be to create it in AppModule and annotate provide method and app component with singleton annotation.
If I build a component in the application class, does that mean all
the object instances available through this component will be a
singleton instance throughout the app until the app is killed or
restarted?
If you annotate provide methods with #Singleton annotation then yes
I have a component with a custom scope let's say #ActivityScope, and I
build that component in an Activity, will the object instances
injected through this component be destroyed automatically after this
activity's onDestroy() is called?
Yes
Again I have a component with a custom scope let's say #ActivityScope,
and I build this component in ActivityA and ActivityB, will ActivityA
and ActivityB share the same object instances from this component or
they will have their own instances of the same object?
They will have their own instances
I am new to Android development. After learning from many tutorials I got many Activities and many Fragments. How can I make a core engine to check what Activity is running and what Fragment is showing on a container?
Assume that I have:
Acivity01, Activity02, ... , Activity10
Fragment01, Fragment02, ... , Fragment10
I want to make a class that filters the Activity where Activity is on runtime and what Fragment is embeded to that activity.
How can I do this?
If I understand you correctly, you may want to store some references within your Application class to an Activity and to Fragment instance(-s), which are currently in foreground (by this I mean that user can instantly interact with Activity/Fragment).
As for Activity
Create some Activity field in your Application class and getter/setter methods for it (e.g., setCurrentActivity(), getCurrentActivity()). Then call setCurrentActivity() from onResume() method for each of your Activity instances. Don't forget to call setCurrentActivity, supplying null reference to ir in order to properly handle a case, when there are no foreground activities, but application is stll working.
As for Fragment
The general idea is similar to the first item, but there can be more than one Fragment instance in foreground state at time. So you need to store something like List, where you add your resumed fragments and remove paused.
You may also want to implement something similar for dialogs, for example. Then use the same strategy. Hope it will help.
I have an android application with a number of activities.
I have a singleton class holding my main data model which all activities access to get data.
The problem is that sometimes the android GC decides to destroy my singleton when the app in the background (when you press the home button).
Is there anyway that I can bypass this?
I've had this exact problem in a current application of mine, which needs to retain a large amount of data in various 'singleton' classes. The problem I encountered was as in your case; i.e. sometimes when bringing the application back to the foreground, some of the static 'singleton' classes have been destroyed.
The problem, I believe, is that the 'lifetime' of such classes can never be well defined or predicted. After all, it's a class sat there holding a reference to itself, so it's susceptible to being garbage collected when the system wants to grab some resources.
You're probably already aware that extending android.app.Application is a well-known alternative to using conventional Singletons. The solution that worked for me is to hold the actual instances of data singleton classes within an extension class of android.app.Application, whose lifecycle is well defined. Any other class that wants to access those singletons can obtain them using a getter in the Application class.
So for example I have a class called AppState that extends Application, that holds the instances within:
import android.app.Application;
public class AppState extends Application {
...
// "Singleton" instances that this Application extension looks after
private MSData singletonInstanceMSData;
public AppState() {
...
singletonInstanceMSData = new MSData();
...
// ---------------- Singleton instance control ----------------
public MSData getMSData(){
return singletonInstanceMSData;
}
// I also provide the means to 'reset' the instances on startup (this is
// something I need to do for my application - you may or may not need to)
public void resetControllerSpecificData(){
singletonInstanceMSData.reset();
...
Don't forget you'll need to modify your manifest if you extend Application.
AFAIR, lifespan os singleton is lifespan of his classloader - also complete VM . When user hit home button, your application goes in backgorund and is probably destroyed - you can not do anything against it. Your best bet is to save whatever is necessary in your onPause() callback ( or just use write through in every change of datza if you really paranoid )
My Activity is injected with a number of objects that are initialized
before onCreate is called for the first time.
When my Activity finishes by invoking the finish method, it passes
through onDestroy before returning to the main "OS desktop" window.
I then invoke my application again, and onCreate is again called.
This time though my view remains the same as when finish was initially
called above.
Therefore, I am wondering if RoboGuice re-instantiates the injected
objects again? If not, is there a way for me to do this?
Thanks.
are you saying that these are not re-instantiated then?
when onCreate() is called ex. when you change phone orientation every object are injected once again. But if one of injected object is Singleton, the same instance of object will be injected. "Singleton" works in scope of whole application so the activity lifecycle does not ifluence on signleton objects.
Take a look at the Android activity lifecycle docs.
If onCreate is called by Android then a new instance of your activity was created and any non-singleton components will be instantiated, and all components will be injected by roboguice.
If you only need a single instance of a component you can make it a singleton. Just be cautious of memory use with singletons because they will live for the duration of the application process. So even if an activity has been destroyed but your app process is still running those singletons will be consuming memory.
Roboguice is just a wrapper around guice. If you are interested in pursuing other options for getting instances of classes take a look at Bindings, Scopes and Providers in guice.