Android: Using Context statically and in singletons

In Android, you need context for just about everything. If your code is a part of an Activity, that’s easy. But what if you have some non-UI singleton class, which is used from lots of Activities and other non-UI classes?

Android design documents strongly suggest that you just pass a context to it for every use.

public class Worker {
    public Worker getInstance() {
        // return singleton instance
    }
    public void doStuff(Context context) {
        context.getCacheDir();
        // save stuff to cache
    }
}

public class MyActivity extends Activity {
    public void callWorker() {
        Worker.getInstance().doStuff(this);
    }
}

This is fine, as long as your doStuff() is very simple. But what if you want to save and reuse context in Worker, and your doStuff() is absolutely not guaranteed to be called from an Activity? If you really don’t care, you could just do it like this:

public class Worker {
    private static Context context;
    public Worker getInstance() {
        // return singleton instance
    }
    public void init(Context context) {
        // this.context = context; // (1)
        this.context = context.getApplicationContext(); // (2)
    }
    public void doStuff() {
        context.getCacheDir();
        // save stuff to cache
    }
}

public class MyActivity extends Activity {
    public void callWorker() {
        Worker.getInstance().init(this);
        Worker.getInstance().doStuff();
    }
}

Application vs Activity context

Note the difference between (1) and (2). Activity context is different from the application context, but in this case either will work. However, with (1), we’re leaking the Activity, meaning it will hog the memory for nothing, instead of being garbage-collected in time. Plus, what if later you needed to doStuff() from another activity? You’d be running in a different activity’s context, and who knows what could go wrong. With (2), you’re saving the application context instead. There’s only one, and it lives for the lifetime of your process.

Lots of internet posts will have you believe that you should religiously avoid application context and only use activity contexts. These are written by students who have never written any code outside of an activity. Obviously, application context is fine, you just need to know what it can’t do.

Static context

However, the example above still sucks. Who guarantees that init() will ever be called before doStuff()? What if you want to use context in Worker’s constructor?

This kind of task calls for some static way to access application context. Generally, static context is essential to design a good singleton. A lot of system features ask for context, while having no earthly reason to use anything other than the application. DefaultSharedPreferences and getCacheDir() are good examples. You can use them in a context-specific way, but you won’t do that 99.9% of the time.

However, even though application context is totally static and lives for the lifetime of an app, there’s no way to get it with, like, Context.getApplicationContext(). The problem isn’t technical, it’s just for some reason Android designers didn’t want you to do this exact thing. Probably because application context can’t do some things activity context does. So instead of designing it in a way that would clearly communicate these limitations, they just said people shoudn’t use it.

Common way to work around that is subclassing the Application and keeping a static reference to it.

public class App extends Application {
    private static Context appContext;
    @Override
    public void onCreate() {
        super.onCreate();
        appContext = this;
    }
    public static Context getAppContext() {
        return appContext;
    }
}

Again, in every discussion of this method (like this or this), you will find this obligatory quote from Android documentation:

“There is normally no need to subclass Application. In most situations, 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.”

That’s exactly the kind of BS I mentioned earlier. Probably subclassing Application could be avoided, if we had a decent way to get static application context. You may also get the feeling from this quote that it’s somehow unsafe. It isn’t, it’s just frowned upon.

There is a downside though. Normally you’ll also want to shove lots of static fields in the App class, to keep your useful global variables and whatnot.

public class App extends Application {
    private static Context appContext;
    private static SharedFoobar foobar1; // (1)
    private static SharedFoobar foobar2 = null; // (2)
    // private static LootCache = new LootCache(); // (3)
    @Override
    public void onCreate() {
        super.onCreate();
        appContext = this;
        foobar1 = new SharedFoobar(); // (4)
        foobar2 = new SharedFoobar();
    }
    public static Context getAppContext() {
        return appContext;
    }
}

public class LootCache() {
    private final Context context;
    public LootCache() {
        context = App.getAppContext();
    }
}

public class SharedFoobar() {
    private static Context context = App.getAppContext();
}

Note that in (3), LootCache was initialized statically. Which means it will run its constructor and getAppContext() before App had a chance to initialize appContext field, which will cause NullReferenceException later. This seems obvious, but in fact it’s really easy to miss, especially if this constructor in LootCache was added later by someone else.

If you’re familiar with normal languages, you may also think that foobar1 and/or foobar2 have this problem too. Since SharedFoobar has a static initializer, and is declared in both (1) and (2), wouldn’t it want to run static constructor right there? In case (2), it looks almost unavoidable, right? So, no, it will not do that. In Java, classes are not even loaded on declaration, they are only loaded “when referenced”. In our case, this means that static constructor of SharedFoobar will only run on (4).

Singleton pattern

Now that we have a way to statically access the context, we can write a proper Worker singleton.

public class Worker {
    private static Worker instance; // automatically initialized to null
    public static Worker getInstance() {
        if (instance == null) 
            instance = new Worker();
        return instance;
    }
    public void doStuff() {
        Context context = App.getAppContext();
        context.getCacheDir();
    }
}

See how doStuff() immediately became easier? We don’t have to pass Context to it from millions of places, or worry about is that the right context, or will it be leaked there, or any of that stuff.

If you’re an experienced dude, however, right about now you should say “ha-ha, you dumbass, getInstance() isn’t thread-safe”. That’s true. You could make it thread-safe like this:

public class Worker {
    private static Worker instance;
    public static synchronized Worker getInstance() {
        if (instance == null) 
            instance = new Worker();
        return instance;
    }
}

But as it turns out, in Java, there’s a fantastic alternative to this universal pattern. Since Java classes themselves are lazy-loaded, you can just initialize the instance statically. It will be loaded on first use of the class and is thread-safe “by design”. Read google groups discussion (subj is “Android LifeCycle and Singleton Instances”) and this post on double-checked locking. (* see Update 1 & 2 below)

public class Worker {
    private static Worker instance = new Worker();
    public static Worker getInstance() {
        return instance;
    }
}

The “null static” case

Let’s circle back for a bit. On this point, you may consider this implementation equally good:

public class Worker {
    private static Context context;
    public static void init(Context appContext) { // only call from App!
        this.context = appContext;
    }    
}

public class App extends Application {
    public void onCreate() {
        Worker.init(this);
    }
}

Since Worker will definitely be initialized in App.onCreate() and only there, Worker.context will always reference Application, right? Turns out, no, it can unexpectedly reset to null. This is a rare case which people usually discover on production, and go like “how can that be? It’s static!”

So, if your app is in background and system runs out of memory, it will start unloading classes (* see Update 3!). At some point, it may go ahead and unload Worker class. Next time you use it, it will be reloaded, and static variables will reset to default values. Since app itself never went out of memory entirely, there will be no call to Application.onCreate and no init(). Hence null context.

In other words, there’s absolutely no guarantee that Worker will initialize once per process. Every time you getInstance(), there’s a chance it was just recreated.

This issue is very poorly (read: not) documented in official documentation, so people are usually confused and scared about it. Then they discover that statics in App class are never unloaded like this (because App is guaranteed to live as long as process), and say “singleton yourselves, Android team, I don’t trust you now and will do the exact opposite of what you recommended”.

public class App extends Application {
    public static Worker worker;
    public void onCreate() {
        worker = new Worker();
        worker.init(this);
    }
}

This pattern will also work, and it kinda feels safer, because you don’t need to think about this reloading issue. But there are many cases when you’ll be perfectly fine with reloading, so you’ll just end up locking memory for no apparent reason.

Let’s check one more time, is this pattern affected by the reloading issue?

public class Worker {
    private static Worker instance = new Worker();
    private static Context context = App.getAppContext();
}

No, it’s not. If the class were reloaded, next time you call it, it will re-init its static members, so neither instance nor context will be null.

On the other hand, if Worker keeps some data you expect to change, you definitely have to make it an App static. Or, alternatively, persist the data every time.

public class Worker {
    Integer somedata;
    public void setSomedata(int value) {
        somedata = value;
        // save somedata to persistent storage like SharedPreferences
    }
    public int getSomedata() {
        if (somedata == null)
            // load somedata from persistent storage
        return somedata;
    }
}

I hope this post helps someone with all this confusing stuff.

PS: Updates

After this post was written, I’ve had interesting discussions on the subject and found that some of my statements were incorrect. Here are some updates on this.

Update 1: “final” matters

Notice that in previous examples I declare a lot of variables static, but not final. I never thought twice about it. Yes, they could potentially be changed, so I guess don’t change them. As it turns out, it does matter from the thread safety point of view. A “static final” variable is completely thread safe, while just “static” has to be synchronized. Read this StackOverflow and this Java document. So, correct example of my favorite singleton would look like this:

public class Worker {
    private static final Worker instance = new Worker();
    public static Worker getInstance() {
        return instance;
    }
}


Update 2: double-checked locking works

The issue with this pattern was related to operator reordering and specifics of “volatile” keyword. The article I read about this is quite old. So as it turns out, the “volatile” keyword was fixed in Java 5, and this pattern works now. It’s still gross and I would rather use the alternative, but there it is. See Wikipedia.

Update 3: classes do not unload (except sometimes they do)

Last time I researched this subject, I found a lot of anecdotal evidence that individual classes can be unloaded separately. I was relatively new to Java and it was generally weird to me, so I thought, that’s pretty disgusting, but okay. So now I took a second look, and it doesn’t really work like that. According to this post, it used to work exactly like that in some ancient Java, so that’s where the rumor comes from. In current version, specifically in the Android Java (whatever version that is), classes NEVER UNLOAD. We have that on good authority here.

But then again, the statement above is not the entire truth. Classes can in fact unload. But, only when all classes of a particular classloader decided to unload (aka were garbage collected). See this discussion. Also “JNI Tips“, which is an official document, mentions this case in an usual brief and confusing manner:

Classes are only unloaded if all classes associated with a ClassLoader can be garbage collected, which is rare but will not be impossible in Android.

Now, you might not know what a classloader is (which is normal and not a shame). Let’s just say java classes are also objects. Sounds like something a crazy person would say, but it makes sense to me. And there’s a collection or something where these objects are referenced. So when all objects are unused, and the collection is unused, logical step is to go ahead and garbage collect the entire thing.

Android apps happen to have two classloaders: a system one and an app’s one. I don’t know for sure why, I guess to make things complicated. But the app’s one basically references all your custom stuff. So if you don’t know about classloaders, don’t worry: only way yours will ever be unloaded is together with the entire app, after which point it will just be the same as a cold restart. You can however screw things up in an interesting way by using custom classloaders.

So, given all that, how come “null static” issue still exists? My guess is, it’s a combination of several scenarios described above. Like, doing stuff before App.onCreate(), or from an activity lifecycle event (and then the activity itself unloads and reloads in hilarious ways), or not realizing that classes with all their fields are in fact lazy-loaded. This post gives some more info (even though the author disses singletons, which I think is acrimonious of him). Also here and here are good practical examples.

Personally, I actually find it useful to think of a static as something that can be reloaded at any moment. Like, let’s say this class suddenly died and then re-inited, can it re-init its statics from some persistent storage or whatever? If the answer is no, then there’s a possibility for a problem.

Advertisements

5 responses to “Android: Using Context statically and in singletons

  1. Kevin Galligan (@kpgalligan) August 17, 2014 at 03:07

    We wind up with a custom Application class on almost every project. As the single point of startup, onCreate is pretty useful. I struggle with keeping a static Application reference there, but there’s no technical reason not to do that. Just habit. Have had this discussion several times. Will probably just bite the bullet and keep the static ref.

    Like

    • nfrolov August 17, 2014 at 07:35

      I noticed that lots of people go with the custom Application. I kinda have a feeling that Android designers intended the system to work like web applications, with stateless web pages and all that, but they overdid it a bit. Web applications (at least .NET ones) also have shared resources and single startup point.

      Like

  2. derp June 15, 2016 at 03:30

    In Android Studio (2.2 Preview 3), it still complains about this line:

    private static Context context = App.getAppContext();

    “Do not place Android context classes in static fields; this is a memory leak (and also breaks Instant Run) less…
    A static field will leak contexts.”

    Liked by 1 person

  3. Pingback: Using Context statically in singletons | SLED5.NET

  4. igor.ganapolsky December 15, 2016 at 19:19

    I am curious, would using dependency injection framework like Dagger solve the problem of Context singletons? I mean, Dagger will maintain the lifecycle of this singleton for you.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: