Latest Tweets

 

Global Application State in Android

All applications carry some global state and Android applications are no different, but their componentized structure and the constraints of the hardware they are intended to run on throw up some new code design considerations.

Complex Android applications will have many possible entry points, for instance a user might activate the application from a launcher, or from a notification, or to fulfil a request by another application altogether, so you can’t make many assumptions about ‘where’ your application is going to launch from.

At the same time, the limited processing capacity available means that its important to avoid repeating work, so there are generally resources that you want to cache. But you will probably find that most of these resources will depend on a Context, so its not simply a case of hiding their acquisition behind static accessors as one might in a typical desktop Java application.

In addition, application management in Android puts a premium on rapid application start-up — users have every right to expect responsive applications — so in non-trivial applications it’s usually not the case that you can simply initialize all your global state because much of it may be wasted depending on how the application was launched.

My preferred approach is to sensibly modularize my global state and attach it to an Application instance that initializes it lazily behind static accessors. I’m not saying this is the only approach, or even the best, but it’s the one I use.

Since the Application component is always the first thing to be initialized in your application, you don’t need to worry about whether it’s ‘ready’ when you call it from other components (important caveat ContentProviders are started before the Application). Furthermore, if there is state you know you will always need when your application is launched, its onCreate() is an ideal place to do that work. Finally, and this is its most important benefit in my opinion, helper classes that need to hold-on to a Context to do their work, can do so permanently without inadvertently pinning an Activity or Service in memory. Of course, nothing stops you from being careful with the Context objects you choose to initialize your context dependent classes with, but this approach means you don’t need to be overly mindful of it.

import android.app.Application;
import android.content.Context;

public class MyApp extends Application {

    //sensible place to declare a log tag for the application
    public static final String LOG_TAG = "myapp";

    //instance 
    private static MyApp instance = null;

    //keep references to our global resources
    private static SomeResource someResource = null;
    private static AnotherResource anotherResource = null;

    /**
     * Convenient accessor, saves having to call and cast getApplicationContext() 
     */
    public static MyApp getInstance() {
        checkInstance();
        return instance;
    }

    /**
     * Accessor for some resource that depends on a context
     */
    public static SomeResource getSomeResource1() {
        if (someResource == null) {
            checkInstance();
            someResource = new SomeResource(instance);
        }
        return someResource;
    }

    /**
     * Accessor for another resource that depends on a context
     */
    public static AnotherResource getSomeResource2() {
        if (anotherResource == null) {
            checkInstance();
            anotherResource = new AnotherResource(instance);
        }
        return anotherResource;
    }

    private static void checkInstance() {
        if (instance == null)
            throw new IllegalStateException("Application not created yet!");
    }

    @Override
    public void onCreate() {
        super.onCreate();
        //provide an instance for our static accessors
        instance = this;
    }

}