Is it safe to save the app context to a static variable in Android?

15,116

Solution 1

is it safe to save the app context to a static variable?

Presently, yes, it appears to be safe, though I would not have getAppContext() return Context, but instead return App or Application.

That being said, the fact that the core Android team did not set it up this way in the first place suggests that perhaps there may be hidden issues of which we are unaware, or that in the future this approach may introduce problems.

As the acronym of the saying goes, YMMV. :-)


EDIT

if so , is it also safe for any other class to have any kind of reference to the application context ?

I have no idea what you mean by "safe" here.

but if i use multiple processes , i will get totally different references to App class on each process , right?

If you use multiple processes, you should be slapped with a trout. But, yes, you should get distinct App instances per process.

Solution 2

It should be safe. Also the following note from the API docs could be relevant to you:

There is normally no need to subclass Application. In most situation, static singletons can provide the same functionality in a more modular way. If your singleton needs a global context (for example to register broadcast receivers), the function to retrieve it can be given a Context which internally uses Context.getApplicationContext() when first constructing the singleton.

Solution 3

It's safe to do this in Application#onCreate() because the Application is created before any activity. If your app gets killed in the background, the Application instance will be recreated and your global will be set before any activity runs.

It's important to note that you should never set global variables from an activity. If you do, your app could fail in the following way:

  1. Set global in activity A
  2. Navigate to activity B
  3. App goes into background
  4. Framework kills app and process
  5. App is restored
  6. Framework creates activity B. Activities in the backstack are not created until you navigate back to them, so the global is not set!
  7. Activity B attempts to use global, and boom... NullPointerException

Solution 4

Interesting comment popped up from Studio when I was tidying up nasty static contexts:

"This is a leak (and also breaks Instant Run)."

So with the launch of Instant Run, we have the case where Android developers are not planning on saving static variables. Whilst instant run is not (yet) on my agenda, it is useful to know that there is a specific example where it is not only bad practice, but the use case where it is wrong is identified.

Share:
15,116
android developer
Author by

android developer

Really like to develop Android apps & libraries on my spare time. Github website: https://github.com/AndroidDeveloperLB/ My spare time apps: https://play.google.com/store/apps/developer?id=AndroidDeveloperLB

Updated on June 06, 2022

Comments

  • android developer
    android developer about 2 years

    I know that usage of static variables on Android is quite risky, especially if you reference them to activities. However, if I have a class that extends Application (let's call this class "App"), is it safe to reference to the instance of this class?

    If so, is it also safe for any other class to have any kind of reference to the application context? I mean, can there be a memory leak if I have a reference to the application context in any kind of class?

    The purpose is that no matter in which scope I am in, I can always get a reference to the application context. I think it's safe, since if the system closes the application, the static variable is also gone till the next time the application starts again, which will initialize the static variable again.

    Also, not that it matters much, but if I use multiple processes, will I get totally different references to App class on each process?

    As an example of code, here's what I'm thinking about:

    public class App extends Application
    {
        private static Context _appContext;
    
        @Override
        public void onCreate()
        {
            super.onCreate();
            _appContext = this;
        }
    
        public static Context getAppContext()
        {
            return _appContext;
        }
    }
    
  • android developer
    android developer about 12 years
    so , can you think of any way that will take care of possible problems? should i use WeakReference instead of a hard reference ? also , please try to answer the rest of the questions.
  • CommonsWare
    CommonsWare about 12 years
    @androiddeveloper: "can you think of any way that will take care of possible problems?" -- since we don't know what the possible problems are, it is impossible to design a solution for them.
  • Caumons
    Caumons about 12 years
    I also thought about your approach some time ago, as it is not comfortable to pass context every time... I guess you initialize this static variable from your main Activity, am I right?
  • android developer
    android developer about 12 years
    you don't have to . you can set the manifest to set the App class to be the one that extends the application , as written here : developer.android.com/reference/android/app/Application.html
  • android developer
    android developer almost 12 years
    yes . is it true that static variables work weird in android ? for example , if the app uses too much memory , some classes will be unloaded , so if they contain static variables , they will be gone too?
  • android developer
    android developer over 11 years
    @Nate , kindly give some reference to any google website that says that it works this way . some developers claim it work this way and some say it doesn't (like the user CommonsWare ). so this is a very confusing topic.
  • Nate
    Nate over 11 years
    @androiddeveloper, I didn't get this off a website. I got the information by testing on real devices, which is a stronger reference than any documentation. Here's a sample of how to reproduce such behavior. Get a tool that allows you to manually clean memory. For example "Go TaskManager EX". Run your app. Press the home button. Clean Memory. Return to your app in the debugger. Observe static variables in the debugger. BTW, I've seen this on devices without running Go TaskManager. It's just that if you want to see something repeatable, right away, you need to sweep memory yourself.
  • Nate
    Nate over 11 years
    @androiddeveloper, also, I was responding to a general statement you made. It looks to me like CommonsWare was responding to a specific question about a static in the Application class. It may very well be that Android handles the Application class differently than others, and will not attempt to clean it up (without a full shutdown). I was responding to your comment under this question, which was a general statement. In general, Android handles static variables differently than a desktop OS normally would, and they can be cleaned out.
  • Nate
    Nate over 11 years
    @androiddeveloper, also, if your static variable is used for a Singleton pattern, that's probably also safe, because the Singleton normally just caches the instance, and every time it's requested will check to see if it exists, and if not, will instantiate it. If Android cleans the static instance, it may mean your program needs to recreate the Singleton, but that shouldn't break functionality. In other cases of using statics, though, you can certainly encounter full-blown bugs if you lose a static variable you weren't expecting to.
  • android developer
    android developer over 11 years
    according to the user "CommonsWare" (which has a lot of reputation here) , static variables do not get null even on high memory usage . only if the process itself is killed the static variables get to be null-ed . here's a link of some of his answers regarding this issue : stackoverflow.com/search?q=user%3A115145+static+android .
  • Nate
    Nate over 11 years
    @androiddeveloper, please give me a specific link, if you think CommonsWare has said that. His answer to this question is not equivalent to the statement you made earlier. Also, did you even try the test I suggested? I'm sorry, but I don't care how much reputation any one user has. A test is a test. Run the test, and see for yourself.
  • android developer
    android developer over 11 years
    ok , i've done the test and nothing special has occurred to the static variable (remained with the same value) , and the process also wasn't killed since i was able to resume the last activity that was opened. about the links , here are some of them: stackoverflow.com/a/5105220/878126 , stackoverflow.com/a/5306561/878126 , stackoverflow.com/a/4707372/878126
  • Nate
    Nate over 11 years
    @androiddeveloper, ok after re-reading your comment before last, you injected something very important, that was not in your original statement. That's the part about the process. Low memory conditions can absolutely cause the process to be killed, which clears out static variables. But, when an Android app is relaunched, after the process is started, it doesn't start from the main Activity. It starts with where the user left off. So, what you see is the app running in the middle of the code, with the static variable having changed.
  • Nate
    Nate over 11 years
    @androiddeveloper, so what you get is some Activity that's normally only reachable after some navigation through your app, that originally had some static variable initialized, and now it's gone. For all intents and purposes, this is just as startling to most new Android devs as if the original process just cleared out a static variable without being killed. You still have to write your code to handle that situation.
  • Nate
    Nate over 11 years
    @androiddeveloper, regarding CommonsWare's comments, the first one I have some issue with, but only in the wording. He concedes that Android may kill your process, but claims that to be rare. Rare is a term subject to interpretation. It happens all the time, unless you have a gigantic device, don't use many apps, or reboot constantly. If he's not coding his software to handle that, then it's poor software. The middle link concerns services, not apps, and thus is irrelevant. The last link really doesn't say much, other than that a process is cleaned up eventually (vague again).
  • android developer
    android developer over 11 years
    in the test i've made , the static variable wasn't store in an activity . i've used the same tool you've suggested and i think that since it didn't kill the process of the app , the static variable remained fine . so this test doesn't mean anything . please let's summarize it and tell me if the next sentence is correct : the only way for a static variable to be null (without me telling it to be null) is if the process was killed so the app restarts itself .
  • Sky Kelsey
    Sky Kelsey over 11 years
    I'm probably late to this thread, but what I have observed is that you need to be weary of static variables, because when the Activity that initialized them is destroyed, those variables could be lost as well. If you are developing a single Activity Application, then you are safe, but if you are developing with multiple Activities, you need to make sure all of them check and initialize the static variables you intend to use cross-Activity.
  • Martin Marconcini
    Martin Marconcini about 11 years
    ALso late, but I've seen static variables die (even those that live in my Application instance). The test is easier to perform if you leave the app overnight for example. I see a lot of logs that say "xxx instance is null!" in the Getter/Setters, where there's no code that nulls those instances in my entire application. So it's safe to assume that Static variables can (and possibly will) die. I've seen this happening more on pre ICS devices more often (but not restricted to).
  • Ewoks
    Ewoks about 9 years
    @CommonsWare do you still think this is appropriate/valid/good answer?
  • Ewoks
    Ewoks about 9 years
    and this will eventually not lead to memory leaks?
  • CommonsWare
    CommonsWare about 9 years
    @Ewoks: As I wrote in the answer, it appears to be safe. AFAIK, it should be safe. But I wouldn't do it, because I am concerned that in the future it might not be safe.
  • Jones G
    Jones G over 3 years
    You have a warning but did not show the code that solves this.