55

Per the Android Documentation it states:

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.

How do I go about creating a static singleton that has global context so that it survives the running activity changing in my app? Is it enough to have a static context which references the getApplicationContext()?

Amokrane Chentir
  • 29,907
  • 37
  • 114
  • 158
Derek Gebhard
  • 917
  • 2
  • 10
  • 15
  • 6
    A singleton has a static instance, and once initialized it will 'live` as long as your process lives. What exactly is your problem? – Nikolay Elenkov Dec 27 '12 at 15:47
  • Got it. After first reading the second part of the paragraph above I thought it meant I needed to do something with getApplicationContext() in order for the static singleton to live for the life of the Android Application. After reading it again I think it just means if you need to use context save a reference. Ex: `public static MyObject getInstance(Context c) { }` – Derek Gebhard Dec 27 '12 at 16:20
  • 1
    Yes, something like this. You can make the parameter `Application` to be a bit more typesafe and guarantee that you don't get an activity, etc. context passed. Also, you don't really need to save the context, just initialize what you have to with it. – Nikolay Elenkov Dec 27 '12 at 16:23
  • Is the Lifecycle of using a standard static singleton the same extending the Application Object? Ex: Will a process for app last longer if the app object is extended? – Derek Gebhard Dec 27 '12 at 16:24
  • 1
    It depends on how you understand 'lifecycle'. Both live for the duration of your process. `Application` has an `onCreate()` that is guaranteed to be called before your activities are started. For a singleton, initialization happens when you call `getInstance()` for the first time. – Nikolay Elenkov Dec 27 '12 at 16:26

2 Answers2

92

Another edit to the question (2016)

Lately (as of 2016 and onward) what I've been doing, and would be my suggestion for any developer, is:

Just use Dagger 2. Wherever you need a Context you do:

@Inject Context context;

and that's it. While at it, inject all the other stuff that would be a singleton.

Edited/improved answer (2014)

because this answer is getting kinda-of popular, I'll improve my own answer with example code of what I've been using lately (as of Jul/2014).

Start by having the application keeping a reference to itself.

public class App extends Application {
   private static App instance;
   public static App get() { return instance; }

   @Override
   public void onCreate() {
      super.onCreate();
      instance = this;
   }
}

then on any singleton that needs access to the context I lazy load the singles in a thread safe manner using double check synchronization as explained here https://stackoverflow.com/a/11165926/906362

private static SingletonDemo instance;

public static SingletonDemo get() {
   if(instance == null) instance = getSync();
   return instance;
}

private static synchronized SingletonDemo getSync() {
   if(instance == null) instance = new SingletonDemo();
   return instance;
}

private SingletonDemo(){
   // here you can directly access the Application context calling
   App.get();
}

Original answer

what the documentation is suggesting is to use a normal singleton pattern

 public class SingletonDemo {
    private static SingletonDemo instance = null;

    private SingletonDemo() {       }

    public static SingletonDemo getInstance() {
            if (instance == null) {
                 instance = new SingletonDemo ();
            }
            return instance;
    }
}

and include inside it a method like this:

 private Context context;
 init(Context context){
    this.context = context.getApplicationContext();
 }

and remember to call this to initialise the singleton.

The difference between the Application approach and the Singleton approach and why the Singleton is better is on the documentation same functionality in a more modular way

El Sushiboi
  • 428
  • 7
  • 19
Budius
  • 39,391
  • 16
  • 102
  • 144
  • 3
    The 'remember to call' design always results in someone forgetting to call it :) Also when do you call it? Call `getInstance()` first? The other way around? You see how this can get messy. – Nikolay Elenkov Dec 27 '12 at 16:36
  • no I don't see. You can even use the application OnCreate to call `getInstance.init(this);` or write this same code on the OnCreate of the launcher activity. The point is that the Application is not a class designed to store data, it's to start the application, people are just sticking it in there even thou the documentation advises not to. Another way is to not store context and pass the context if you're calling methods that need it. – Budius Dec 27 '12 at 16:40
  • 4
    The point is, you can do all sorts of stuff, but it's a lot better if you don't have to. And if you create an `Application` class just to initialize your singletons, why are we even having this discussion? Just put a `static getInstance()` on you `Application` class and be done with it. – Nikolay Elenkov Dec 27 '12 at 16:43
  • `and be done with it` it's a matter of proper organisation of which class is responsible for doing what, not just 'be done with it' http://en.wikipedia.org/wiki/Modular_programming but, same I commented on the other answer: that's a design philosophy and different ppl will have different point of view. No case to argue right or wrong, but debating ideas. But SO is not the place to debate ideas, so peace out! – Budius Dec 27 '12 at 18:33
  • 2
    instead of calling getInstance.init(this). can't we just add a parameter to getInstance and we call getInstance(this) and when we initialize the instance we set the application context. Isn't that better? – hasan Nov 19 '13 at 11:55
  • you can organise it however you prefer. To be honest nowadays (almost 1 year after the original answer) what I'm doing is have 2 methods `public static void init(Context c)` and `public static ClassName get()`. So I call `init` on the application and the rest just call `get()` – Budius Nov 19 '13 at 13:11
  • Why is the conditional `if (instance == null)` there twice (nested in each other)? – Natix Dec 29 '13 at 22:30
  • @Natix I actually have no idea why. LOL. Probably a bad copy and paste. I'll edit the answer. Nice catch. – Budius Jan 07 '14 at 11:05
  • It is not possible that, for example, thread A and thread B calls getInstance. Thread A switch context right after "if (instance == null)" and before "instance = new SingletonDemo ();" and thread B go through the getInstance method creating the new instance. Thread A will create a new instance. I'm wrong? doesn't getInstance need to be synchonized? Or even better, create the new instance in "onCreate" – Emaster Jan 09 '14 at 01:04
  • hi @Emaster yes... check my improved answer – Budius Jul 16 '14 at 08:35
  • That made a difference! Thanks a lot. I'm using this to access globally an expansion file for android. – tvieira Oct 31 '14 at 17:12
  • Instead of having init and the caller forgetting to call it, why don't you create a singleton with a Context variable. When you call getInstance(con), it will save that con as its variable. .Any problems with this? – Snake May 01 '16 at 21:06
  • 2
    There is no guarantee that the non-static `onCreate()` will have been called before some static initialization code tries to fetch your Context object. – Yousha Aleayoub Sep 07 '16 at 22:50
  • 1
    as Yousha stated this very important point: how do you know that the app's onCreate() is called before any static code? – Raphael C Oct 05 '16 at 10:54
  • @RaphaelC Because static code is called the first time you access that class. That's how the Java VM works – Budius Oct 05 '16 at 10:59
  • @Budius ah ok. so static code is called before onCreate(). so if I need to create singletons which require Context, I would need to set their Context after their creation? I just looked up a confusing example in Android's documentation here: https://developer.android.com/training/volley/requestqueue.html#singleton In their example, they hold a static reference to Context in a singleton. Android Studio 2.2 Lint says that this causes a memory leak. What are my options: either I am condemned to pass Context as an argument everywhere, or is there a singleton pattern which can work safely. – Raphael C Oct 05 '16 at 12:07
  • It's called before on Application.onCreate if your static code block is inside the Application class. But if you put it on other class it will be fine. – Budius Oct 05 '16 at 17:11
  • per the official android documentation on classes that extend `Application`: "When the application process is started, this class is instantiated before any of the application's components". This verifies that this code is safe, since the `onCreate` of the `App` class will run before anything else, thus initializing the static variable `instance` – jtate Jun 21 '17 at 17:57
  • @Budius since some years have passed, is the solution that uses get() and getSync() still updated and usable and why should I use it instead of using the get() method only? – Link 88 Jan 03 '18 at 15:58
  • 1
    @Link88 All those are just ways to have singleton application and both ways work fine. It's just a matter on how you want to structure your code. Nowadays for anything that is more than "Hello World" I just use Dagger2 to inject anything I need, including Application, Context, Storage, Http Client, etc, etc – Budius Jan 03 '18 at 16:22
4

I have such class in my application :

public class ApplicationContext {

    private Context appContext;

    private ApplicationContext(){}

    public void init(Context context){
        if(appContext == null){
            appContext = context;
        }
    }

    private Context getContext(){
        return appContext;
    }

    public static Context get(){
        return getInstance().getContext();
    }

    private static ApplicationContext instance;

    public static ApplicationContext getInstance(){
        return instance == null ?
                (instance = new ApplicationContext()):
                    instance;
    }
}

and then for example in Launch Activity initialize it :

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //init
    ApplicationContext.getInstance().init(getApplicationContext());
    //use via ApplicationContext.get()
    assert(getApplicationContext() == ApplicationContext.get());
}
Mickey Tin
  • 3,408
  • 10
  • 42
  • 71