Android Studio now displays a warning when a class contains a static Context object. It says this causes a memory leak. However, I have noticed this is also done in android libraries. For instance, the LocalBroacastManager class has a static instance and it contains a context object.
So how bad is this as a memory leak?
I have a singleton geofencing class that runs in the background and saves a boolean to sharedPreferences indicating if the user is in the geofence or not. To save the preferences I need a context object, but since the method is an overridden method, I have no way of passing a context object in.
How can this be accomplished without a context instance variable?
Its about the worst you can have. Lets say that you have an Activity, and store that as a static Context. Unless you null it out when the activity finishes, you now have leaked a whole Activity. That means every variable that the activity holds is leaked, including the entire view hierarchy. Its basically preventing anything in that Context from freeing up.
The best thing to do is not to store a Context, but instead to pass it in as a parameter to functions that need it. If you must store a Context, do not make it static. A non-static variable won't leak it so long as nothing in the framework continues to hold a reference to the object after the activity is finished.
If you absolutely must use a static Context, make it the Application context. That one is valid over the length of your app, so it can't really be leaked.
Statics should be rarely used, especially in Android. There are ways and reasons of using statics, but in 90% of cases, it is just a misuse of them.
Keeping the context as a static variable is a big no-no. Imagine following scenario:
You go from activity A to activity B.
While in activity B you keep activity B reference as static Context somewhere.
You go back to activity A. Activity B should be destroyed, but instead it is kept, since you keep a static reference to it.
Now you go again to B from A, et voila - you have two B instances: the one you see and another one kept as static context.
You may NEVER have two instances of the same activity. It could cause a lot of issues.
Now, I'm aware that a lot of developers (even ones making libraries) every now and then make mistakes and use anti-patterns, so you should not blindly rely on practice/pattern seen in someone other's code. Hell, I've even seen a lot of garbage code in something written by Google devs.
If you really need a singleton (not Singleton pattern (uppercase S)), but single instance of some class, if you don't want to use libraries like Dagger and so, you can instantiate that class in your Application class, and then reference it from wherever you want.
Related
Does it matter whether I access strings from strings.xml file from different contexts?
I accessed it in many ways such as: getApplicationContext().getString(R.string.name), this.getString(R.string.name),MainActivity.this.getApplicationContext().getString(R.string.name), or simply getString(R.string.name).
I understand that the application context lasts the whole application lifetime, but I honestly do not know when I should use it. Also, I cannot understand what is the difference between using this and MainActivity.this.
Please explain how I should access strings from both activities and Java classes.
The key argument for using the Application Context or the Activity Context is the dependency to the lifecycle of the whole App or a component (Activity in this case). If you wanna access the strings.xml it doesn't really matter which of both you use. Because you just use the Context get a reference to the ressource, which goes away when the Activity will be destroyed. A more importent case would be if you pass the Context to another class f.e. Because then there is a dependency to this specific Context and can lead to memory leaks if you don't clean it. There is a nice explanation about this with the usage of a BroadcastReceiver in the docs.
There is no difference between this and AnyClass.this because it points to the same class object. But you have to use AnyClass.this if you wanna access the outer class in an inner class. Or if you have an anonymous class and need to access fields of the outer class. You could see it as more strict because you refer to a specific class.
I have a multi activity application and save data in the main menu activity that is used by many of the other activities.
One of my variables in the Main activity might be this
static double targetAngle = 45;
I might call that variable from another activity like this
diff = Main.targetAngle - angle;
or I might set it like this
Main.targetAngle = angle;
From this reference, http://developer.android.com/guide/faq/framework.html This seems like a correct way to pass data. But there is always talk about activities being killed by the OS at any time.
My question is, is this safe or not?
As an alternative, I have at the suggestion of SO members, a Class called Helper that has some functions that are used in every activity which also have some static data. For example, the Helper Class has this data followed by my functions
public class Helper {
static double[] filter1 = new double[]{0,0,0,0,0};
static double[] filter2 = new double[]{0,0,0,0,0};
static double cog = 0;
...
various functions....
}
I could save my shared variables in that helper class if that would be better. That class is called once a second and if it is ever killed, I am dead and really need to rethink things. I should mention that I have had no issues with what I am doing but one of my users is having his Nexus-7 crash and we don't know why so I was thinking he might have more applications running than I do, thus my question.
I should also mention that if the user exits the application, I have saved any variables that need to be saved in files on the SD card so they can be re-loaded. In other words, the loss of data when the application is killed is not an issue. My question is only if my main activity was killed when the application was still alive.
My thanks to selbie and squonk for answers in the comments. Lacking an official answer from either I post my own as I want to close this out.
What I conclude is that per this post
Using static variables in Android, the static variables themselves are not destroyed and what I am doing is safe.
This post, Clearing Static data onDestroy() states that "The value of static variables will persist as long as the class is loaded...The only reason ... that Android will unload a class is that your app gets completely removed from memory"
However, it may not be good practice as pointed out by squonk. Using a Class that is not an Activity to host static global variables and common functions may be better practice and is easier to maintain and generally cleaner. I will be moving in that direction as it has other advantages as well.
In either case, it is clear that when the application is destroyed, the variables will be re-initialized and needs to be reset manually. In my case, I store data on the SD card in files, which is one of several ways to save data.
I found the above links with a new Google search. Obviously I should have done a search with that wording earlier but none of my searches returned useful results, mostly finding the singleton vs extension of application debate.
static variable cannot use over through Activity. As you said, they become initial value when you called again from another activity even you assign value.
Use SharedPreference or pass value with Bundle.
I am following some tutorials for learning android but the problem is they do not contain all the details.
Specifically, it would be great if some light could be shed upon the use cases for getApplicationContext().
You can think of a Context as a handle to your application's resources (i.e. everything in the res folder) and to the Android runtime. Classes like Activity, Service, Application inherit from Context, among others.
Typically, you'll pass in the current Activity whenever a Context is required, since Activity inherits from Context.
You'll also find information about using getApplicationContext() instead of your activities when a Context is required. This usually is to prevent whatever code that needs the Context from unnecessarily holding a reference to your Activity, which in the worst case might preventing it from being garbage collected (passing in the Application isn't really a huge problem in that scenario, because it's expected to be around for a long time).
However, there are certain scenarios where an argument of a method is of type Context, but an Activity is actually required. Using startActivity() is one example of this I believe (correct me if I'm wrong).
I have a simple Android application that uses an instance of a class, let's call it DataManager, to manage access to the domain classes in a Façade-like way. I initially designed it as a singleton which could be retrieved using static methods but I eventually got irritated with the messiness of my implementation and refactored to what I reckoned was a simpler and cleaner idea.
Now the idea is that for each file that is opened, one DataManager is created, which they handles both file I/O and modification of the domain classes (e.g. Book). When starting a new Activity, I pass this one instance as a Serializable extra (I haven't got on to using Parcelable yet, but expect I will when I have the basic concept working), and then I grab the DataManager from the Intent in the onCreate() method of the new Activity.
Yet comparison of the objects indicates that the object sent from one activity is not identical (different references) to the object retrieved from the Bundle in the second Activity. Reading up on Bundle (on StackOverflow, etc.) suggests that Bundles cannot do anything other than pass-by-value.
So what is likely to be the cleanest and safest strategy for passing an object between Activities? As I see it I could
Forget about passing by reference and live with each Activity having its own DataManager object. Pass back the new DataManager every time I close an activity so that the underlying activity can use it. (The simple solution, I think.)
Go back to using a singleton DataManager and use a static method to get it from each Activity. (Not keen on using singletons again.)
Extend Application to create a sort of global reference to DataManager. (Again, not keen on the idea of globals.)
Is that a fair summary? Is there some other healthy strategy I could use?
Another approach would be to create a service. The first activity would start the service and bind to it, when you launch a new intent, unbind the first activity and when second activity starts, bind to the service.
This way you don't have to ever stop the service or worry about passing data between activities.
Java does not have pass by reference so that option is out, I would suggest dependency injection for passing data between the activities. Otherwise definetely the singleton would be the way to go.
The prescribed one is Going by implementing Parcellable interface, thats the way to pass Objects between Activities.. and the 2nd and better choice is to make a Singleton to be sure its single Object.
Create your DataManager as a Singleton that implements Service. Bind the service to your application in the manifest xml (see the link), and you will have a persistent singleton your activities can access without issues.
Passing parcellable arguments can quickly get very messy if you need to get a lot of data. The singleton approach, although usually considered an anti-pattern, works like a charm in cases like these. Just remember to not create multiple singletons that interact with one another.
I would suggest using an Application Subclass. It allows you to hold a single reference to the DataManger class and is persistent as long as your app lives.
A singleton with a static field will also work, but there are some place in the documentation where it says that the content of static fields is not a safe place to store your data. As I understand static fields should persist as long as your ClassLoader stays in memory. Therefore a singleton should only vanish if the whole process leaves the memory and in that case the application class will also leave the memory, but it will call the onDestroy methods of the Application and that enables you to safely close your DataManager and persist important data to memory.
That said to your two variations.
The Android way to go would be to make your DataManager a ContentProvider. This will make it possible to access your Data from every Activity without holding a global reference. I'm not sure how you would build a caching Content Provider that stays in memory and is not reinstantiated too often.
So far, to accomplish certain functional goals, I have been getting away with handing out my app's main activity object as a parameter to the constructors of other classes, which then store it as a private variable.
I do this, not because I need access to the entire activity, but rather because I need access to:
Members (either data or
methods) of the activity
Data members which aren't initialized yet
at the time those constructors were
called.
It works, but I have the constant feeling that I am doing something fundamentally wrong in terms of proper OOD.
Especially in regard to point #1:
The members that are so "private" to
Activity become, in essence, a pool
of global variables mess.
In addition, those other classes
that were created for the purpose of
modularity, are now dependent on
knowledge of the activity class,
which makes them not really
re-usable outside this app...
For these reasons, I try to avoid passing an activity as a parameter to constructors as much as possible, but in the Android development environment I find it more difficult to do, for reasons I don't fully understand yet.
My questions:
Are there recommended "rules of
thumb" that can help avoid this
trap of taking "a shortcut" by
passing an activity as a parameter?
Are there cases in which passing an
activity as a parameter is
conceptually justified?
Generally speaking, you should avoid keeping references to the activities. If you really need, store a WeakReference to your activity. This is to avoid memory leaks.
As you said, by passing a reference to an activity, you introduce a dependency between the other object and your activity class. Give some sample code so that we could give an example of how to refactor it.
I have found it best to keep values that multiple classes will require in a separate Util class. That way, you do not have to pass the main Activity around to other classes.
An alternative to this is to pass the required values that the main Activity has as parameters to the other classes as needed.
To your 2nd question, I cannot think of any reason that you would have to pass your main activity and then call methods on it.