Lots of developers love the Application class as a container for application-wide resources, because:

This, however, is actually a really bad idea that will only cause you pain, for two main reasons:

I’m going to explain these reasons in detail, but first, I’ll show you how not to do app-level state, using an example app that I just made up. It’s called PictoBlaster, because it allows you to apply filters to pictures and then ‘blast’ them to your friends1.

How not to do it

It’s really easy to go down the route of putting resources in your Application class (again, please don’t do this):

Seriously, don’t do this.

Why not?

1. Memory Pressure

Developers often forget that BadApp is loaded into memory when Android initializes your process, and before any other component can be loaded. That’s not a big problem for apps that only have a single Activity, but as soon as you start adding other components (other Activities, Services, BroadcastReceivers, or ContentProviders), BadApp has to load all its dependencies before any of those can be started. This is especially true for components that are supposed to be lightweight, such as BroadcastReceivers and ContentProviders.

Loading those resources burdens the operating system unnecessarily. Consider the following scenario:

So far, so good. The problem occurs when the PictoBlaster process has to be loaded again for what should be a lightweight component:

Not only is this a waste of the users’ battery (how long did it take to initialize all that stuff?), if BadApp initializes enough stuff, it can also create memory pressure that causes other apps to be shut down3. This is especially true if the user’s loaded another memory-intensive app in the meantime.

Yikes.

The root problem: eager initialization

The root problem here is that resources are loaded eagerly on process start, whether they’re going to get used or not. This is almost never something you want. In a resource-constrained mobile environment, it wastes battery and memory, which can kill other apps that the user may be interacting with. That’s a terrible user experience.

It is possible to work around this by making all of your Application-level resources lazy-loaded using an explicit lazy initialization mechanism, such as Guava’s Suppliers.memoize() or Apache Commons’ LazyInitializer. This workaround still doesn’t solve the maintainability problem, though.

2. Maintainability

The other major problem with initializing all your resources in your Application is that it makes it easy to give your Application too much scope. Once there’s a precedent for putting app-wide resources in your Application class, other developers on your team will put them there too. Then, you’ve got a class that owns loads of different resources.4

A side effect of giving your Application too much scope is that if you ever want to reuse code that uses these dependencies, pulling the code out into a separate library isn’t a simple task - you’ve got to decouple your app-wide resources from the Application object first.

A solution: the good old-fashioned static instance

I think that the real reason why a lot of developers like the Application class so much is that programmers have often been taught that static members are evil. Actually, static members are extremely useful whenever you’re working with resources that are scoped to a process (the app, in this case). The Application class represents exactly the same concept, it just allows developers to avoid the icky feeling they get from using static members instead.

Java’s semantics for static members are pretty useful. Static members are initialized when the class is loaded, which means that they’re loaded the first time you use a static member or instantiate the class. This gives you lazy-loading for free, without having to write boilerplate yourself. The ‘static instance’ approach is one that Android framework engineers have recommended in the past.

The idea is to define a class like this:

public class AppWideResource {
  public static final AppWideResource INSTANCE = new AppWideResource();
  private AppWideResource() {}
  // Rest of class implementation goes here...
}

…and then reference AppWideResource.INSTANCE whenever you need one.

There are a couple of disadvantages to this approach:

Likewise, if you need other static resources to initialize your AppWideResource, just add them as parameters to the AppWideResource#getInstance() method.

The structure of this approach means that:


  1. Our metrics look like hockey sticks and we just closed a Series A for $20m, probably. Our logo is the pair of emoji 📷🚀. [return]
  2. An alternative to the BadApp#getInstance() method is to use (BadApp) context.getApplicationContext(). This isn’t any better. [return]
  3. For more on how Android kills processes when memory is low, take a look at ‘Processes and Threads’. [return]
  4. A really good indication that an object has too much scope is when you find yourself mocking things out in tests that seem completely unrelated. If you find yourself doing this, it might be time to rethink your design. [return]