I still completely don't understand memory leaks. I have created custom singleton with static method:
public static AnalyticsHelper getInstance(Context context) {
return analyticsHelper == null ?
analyticsHelper = new AnalyticsHelper(FirebaseAnalytics.getInstance(context)) :
analyticsHelper;
}
and I want to know whether memory (activity) leaks will occur if I instantiate it in Activity. I'm not sure, because other Firebase tools works as ContentProvider and doesn't need Context when instantiating them. Official docummentation won't help me.
The accepted answer isn't correct. Firebase Analytics (and all the other Firebase singletons that accept a Context) don't hold the same context that you passed to it. It will use Context.getApplicationContext() on that Object behind the scenes to get a true singleton Context to hold for the lifetime of the object. This is the way intelligent Android APIs will work that require a Context to hold indefinitely.
The only potential problem in the given code is the fact that it could possible create two instances of AnalyticsHelper when called in rapid succession from two different threads, but that is unlikely.
Related
I know it is possible to inject Context with Dagger. We can see examples here and here.
On the other end, there are numerous posts about not placing context on a static variable to avoid leaks.
Android Studio (lint) also warms about this:
Do not place Android context classes in static fields; this is a
memory leak (and also breaks Instant Run)
I understand that by injecting a Context with Dagger, we are placing it on a singleton class, so context is somehow static. Doesn't this go against the lint warning?
Injecting the context seems to create cleaner code, since you don't have to pass it to several classes (that don't need it) so that they can further pass it to other classes that need it for some reason (getting a resource for instance).
I am just concerned that this may cause some undesired leak or breaks lint in some way.
You should never store/reference activity context (an activity is a context) for longer than the lifetime of the activity otherwise, as you rightly say, your app will leak memory. Application context has the lifetime of the app on the other hand so is safe to store/reference in singletons. Access application context via context.getApplicationContext().
If you are aware of Android lifecycles and are careful to distinguish the Application Context and the Context of Activities and Services then there is no fault injecting the Context using Dagger 2.
If you are worried about the possibility of a memory leak you can use assertions to prevent injection of the wrong Context:
public class MyActivityHelper {
private final Context context;
#Inject
public MyActivityHelper (Context context) {
if (context instanceof Application) {
throw new IllegalArgumentExecption("MyActivityHelper requires an Activity context");
}
}
}
Alternatively you could use Dagger 2 Qualifiers to distinguish the two so you don't accidentally inject an app Context where an Activity Context is required. Then your constructor would look something like this:
#Inject
public class MyActivityHelper (#Named("activity") Context context) {
Note also, as per David's comment, a Dagger 2 #Singelton is not necessarily a static reference.
I'm trying decide which of the following is the proper way to do this:
Calling FirebaseAnalytics.getInstance(Context) from every activity, fragment, and service that I'm logging an event from.
or
Calling FirebaseAnalytics.getInstance(Context) once from Application class and keeping it around as a public static variable. Then, from everywhere I need this I can call `MyAppClass.mFirebaseAnalytics.logEvent()'.
Will any of the above methods have a undesired impact on the events that are automatically collected and/or do either of those have an efficiency gain over the other?
Many thanks!
The documentation states:
public static FirebaseAnalytics getInstance (Context context)
Returns the singleton FirebaseAnalytics interface.
So I don't see any particular reason why you can't just have a singleton instance in your code.
There won't be any noticeable efficiency gains with either approach. If you're looking into the second option, it might be worth considering doing this with dependency injection and a simple wrapper around the analytics instance to increase the testability of your code.
public class App extends Application {
public static App ctx;
#Override
public void onCreate() {
super.onCreate();
ctx = App.this;
}
}
Then in every non contextwrapper inherited class that needs a Context i use it like App.ctx, Ive been using this extensively in my apps and was wondering, is this a good practice or can it lead to memory leak or any other unexpected results?
Regarding the answer provided by Aritra Roy :
There is no guarantee that the non-static onCreate() (where you are
initializing) will be called before any static initialization which
requires the Context
according to google docs :
void onCreate() Called when the application is starting, before any
activity, service, or receiver objects (excluding content providers)
have been created.
Hence, unless your app provide services to other apps which was not my case so far, it is garunteed that any call within your application flow would come after onCreate was called. And static blocks are not called unless needed so any static block would as well be called after onCreate was called.
Your calling code needs to be ready to deal with null values coming
up because of this, which makes the entire thing more inconvenient
not relavant as App.ctx will never be null unless explicitly set to null anywhere on your own code. according to previous point.
This can lead to huge memory leaks issues
That is exactly what i was asking about, this statement can be true or false, but you didnt back it up so its useless. I was actually asking if it can lead and how can it lead to memory leaks.
Can't implement this static Context in a library project because you
can't extend the Application object.
This is incorrect as ive done it myself and it worked well.
IMO its bad practice.
Because if you context for an object or a method of an object its there for a reason and you should pass the specific context that you (Activity,Service, etc.).
I've been writing apps for 4 years and everytime i wrote/saw this type of static context was of lazyness. About the memory leaks- i havent checked it but it could lead to memory leaks. Think about it - if you create a View (i know you wont:) )or other object for example with a static context at the cuntructor (that implies that one of the members need a context attached , most likely) it wont get called by the GC even if its no longer on the activity.
I think it is okay. I have an Android library which implements the same idea (nv-android-base).
From my programming experience of 23 years, what should be blamed here is Android's library design. Although many application life-cycle models such as Applet, MIDlet and Xlet have been designed, implemented and commercially executed in this software industry so far, Android has failed to learn from the experience. Some parts of Android's library tree are terrible in design and android.context.Context is one example among such terrible parts. Android should have provided a means to get the application context from a static context.
This is a bad programming practice. I will highlight few points supporting it,
There is no guarantee that the non-static onCreate() (where you are initializing) will be called before any static initialization which requires the Context
Your calling code needs to be ready to deal with null values coming up because of this, which makes the entire thing more inconvenient
This can lead to huge memory leaks issues
Can't implement this static Context in a library project because you can't extend the Application object.
I am developing an application with custom Application class which initializes a couple of singletons so they live during all application working time. I also have a couple of services in my application which work with these singletons. Is it possible situation that Application class will be destroyed by android with singletons' instances before services so services will not be able to use them? Or application lives always even for services of it's context? What is the best way to find a way out of this situation?
Thanks.
Regarding the application object:
The application object is the main absolute starting point on any Android app. It will always exist before any of the Manifest declared items such as Activity, Service and BroadcastReceiver. So relax that the singletons will be there for you.
Regarding the singleton paradigma:
That's a big discussion topic, you can google more about it so what follows is my personal opinion on it. Whatever is the reason for your singletons (a database, an bitmap caching, a FileUtils) I think it's ok and correct to initialise them on the very first point of entry of your app, which is the Application. But the application itself is not an object meant to carry or hold those objects, that way my suggested design approach is to:
=> on your singleton object/class you'll have to:
private static MySingletonClass instance; // reference to the single object
private MySingletonClass(Context c){ // private constructor to avoid construction from anywhere else
// let's say it needs the context for construction because it's a database singleton
}
public static MySingletonClass get(){ //
if(instance == null) throw new RuntimeException("This singleton must be initialised before anything else");
return instance;
}
public static void init(Context c){ // call the initialisation from the Application
instance = new MySingletonClass(c);
}
=> and then on your Application object you simply init the singleton
onCreate(){
MySingletonClass.init(getApplicationContext());
}
with that way you'll keep the necessary initialisation, enforce the singleton pattern but to access the object you call to that object class not to the application. I know it's just a organisational difference, but I believe that that's what separate good and bad code.
So for example on your service the call is: MySingletonClass.get() and should never be MyApplication.mySingle.
hope it helps.
From my understanding service can't live without application context, service is bound to the application with the Context reference so I think if the application is killed also the Context is killed and that lead that all components are been killed,
you can read here for more info
http://developer.android.com/guide/components/fundamentals.html#proclife
I'm confused on this. Just started android and have a long form that needs multiple activities to bring together an object. I would like to pass the object from activity to activity to build it. After reading the many posts and blogs and the Android Dev pages, it seems for non-persistent data, the best bet is to subclass application or create a singleton. I reviewed this post openFileOutput not working properly inside a singleton class - ideas/workarounds? and now my question is this, Why doesn't a singleton ever get recycled? If we createSingleton() in Activity A, then move to Activity B and we are never passing a reference to the singleton, how does the garbage recycler know that we are going to come back to it again? it seems to me that when Activity A is recycled and we have moved to Activity B that the singleton would die..
If we look at the following singleton..
public final class SomeSingleton implements Cloneable {
private static final String TAG = "SomeSingleton";
private static SomeSingleton someSingleton ;
private static Context mContext;
/**
* I'm private because I'm a singleton, call getInstance()
* #param context
*/
private SomeSingleton(){
// Empty
}
public static synchronized SomeSingleton getInstance(Context context){
if(someSingleton == null){
someSingleton = new SomeSingleton();
}
mContext = context.getApplicationContext();
return someSingleton;
}
public void playSomething(){
// Do whatever
mContext.openFileOutput("somefile", MODE_PRIVATE); // etc...
}
public Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException("I'm a singleton!");
}
}
And we create an instance of it through getInstance(), the class places a single instance of the class into static field, someSingleton. Why is this instance never recycled? If the answer is, "Static fields are never recycled?" What keeps us from using up all of our memory if we have many of them? Simple design considerations? This seems risky if we are using lots of contributed libraries that we have no idea how many static fields are out there. I just have this feeling that there is some fundamental rule that I am missing in OOP as a newb.
The general pattern is to put a reference to your singleton class in a static field. Static fields are not tied to a particular instance so they stick around until the JVM process is alive. It doesn't really matter how many activities access it. If you need to 'recycle' the singleton, maye you don't really need to use a singleton? Or provide an explicit close()/open() etc. methods.
I think the reason that your Singleton's are not getting recycled is because activities in Android aren't destroyed when you think they are.
You pose a question like 'what happens when we move from activity A to B'. But when you do that in Android, Activity A is very rarely destroyed. It usually just goes into the onPause() state. Thus, your Activity A will still be (mostly) intact if and when a user decided to hit the back button enough times to get back to activity A.