497

In an Android app, is there anything wrong with the following approach:

public class MyApp extends android.app.Application {

    private static MyApp instance;

    public MyApp() {
        instance = this;
    }

    public static Context getContext() {
        return instance;
    }

}

and pass it everywhere (e.g. SQLiteOpenHelper) where context is required (and not leaking of course)?

Segfault
  • 8,036
  • 3
  • 35
  • 54
yanchenko
  • 56,576
  • 33
  • 147
  • 165
  • 23
    Just to elaborate for others implementing this, you can then modify the `` node of your AndroidManifest.xml file to include the following attribute definition: `android:name="MyApp"`. MyApp needs to be under the same package that your manifest references. – Matt Huggins Sep 20 '10 at 03:50
  • Why the static? The application instance is *always* created before anything else. Wherever you are expected to access the application context, it will be passed to you as arguments. This approach may complicate your tests. Static-itis promotes common coupling. – Martín Schonaker Oct 14 '10 at 22:41
  • 8
    Just so you know you're returning your application by one of its super interfaces, so if you provided additional methods within MyApp you would not be able to use them. Your getContext() should instead have a return type of MyApp, and that way you can use methods added later, as well as all the methods in ContextWrapper and Context. –  Aug 09 '11 at 01:28
  • 5
    See also http://goo.gl/uKcFn - it's another reply related to similar post. Better set the static variable in onCreate and not c'tor. – AlikElzin-kilaka Oct 31 '11 at 15:44
  • This won't work if your SQLiteOpenHelper is used by a Content Provider, because the Content Provider's onCreate() is called before the Application's onCreate(). – Eric H Aug 04 '13 at 17:02
  • @MattHuggins If my package name is com.example.xyz so under application node can i define it like this android:name="com.example.xyz.MyApp" or just android:name="MyApp". – Shakeeb Ayaz Aug 17 '13 at 07:24
  • @yanchenko: Have you tested the scenario where the GC kills your app? Would your solution still work then? The reason I ask is because there are scenarios in Android where an application may ask for a `Context` to do certain tasks. For example, listening for volume changes initiated by the hardware volume keys. I suppose, in this instance, if the app has already been killed by the GC, then there won't be any `Context` available to use is there? The only solution, then, would be to check for null `Context` and respond appropriately. – ChuongPham Oct 12 '14 at 03:31
  • 1
    @ChuongPham If the framework has killed your app, there won't be anything accessing the null context... – Kevin Krumwiede Apr 24 '15 at 23:14
  • I think you want to call `super()` from your constructor. – Edward Falk Sep 14 '15 at 18:14
  • FWIW, for anyone using `Xamarin` Android, this is built in as `global::Android.App.Application.Context`. – ToolmakerSteve Jan 03 '20 at 23:26

10 Answers10

432

There are a couple of potential problems with this approach, though in a lot of circumstances (such as your example) it will work well.

In particular you should be careful when dealing with anything that deals with the GUI that requires a Context. For example, if you pass the application Context into the LayoutInflater you will get an Exception. Generally speaking, your approach is excellent: it's good practice to use an Activity's Context within that Activity, and the Application Context when passing a context beyond the scope of an Activity to avoid memory leaks.

Also, as an alternative to your pattern you can use the shortcut of calling getApplicationContext() on a Context object (such as an Activity) to get the Application Context.

Pavneet_Singh
  • 36,884
  • 5
  • 53
  • 68
Reto Meier
  • 96,655
  • 18
  • 100
  • 72
  • 22
    Thanks for an inspiring answer. I think I'll use this approach solely for the persistence layer (as I don't want to go with content providers). Wondering what was the motivation behind designing SQLiteOpenHelper in a way that expects a Context to be supplied instead of acquiring it from Application itself. P.S. And your book is great! – yanchenko Jun 12 '09 at 16:39
  • 8
    Using the application context with `LayoutInflator` just worked for me. Must have been changed in the last three years. – Jacob Phillips May 14 '12 at 06:30
  • Are there problems with this approach? Or, is this exact code good for use throughout the app? – Eric Cochran Jun 16 '14 at 20:58
  • 6
    @JacobPhillips Using LayoutInflator without an activity context will miss out on that Activity's styling. So it would work in one sense, but not another. – Mark Jul 20 '14 at 06:23
  • 1
    @MarkCarter Do you mean using the Application Context will miss out on the Activity's styling? – Jacob Phillips Jul 21 '14 at 04:49
  • 1
    @JacobPhillips yes, the Application Context cannot have the styling because every Activity may be styled in a different way. – Mark Jul 21 '14 at 06:58
  • Why does pass the application Context into the `LayoutInflater` cause an Exception? – Alston Oct 12 '19 at 04:13
30

In my experience this approach shouldn't be necessary. If you need the context for anything you can usually get it via a call to View.getContext() and using the Context obtained there you can call Context.getApplicationContext() to get the Application context. If you are trying to get the Application context this from an Activity you can always call Activity.getApplication() which should be able to be passed as the Context needed for a call to SQLiteOpenHelper().

Overall there doesn't seem to be a problem with your approach for this situation, but when dealing with Context just make sure you are not leaking memory anywhere as described on the official Google Android Developers blog.

xarlymg89
  • 2,552
  • 2
  • 27
  • 41
snctln
  • 12,175
  • 6
  • 45
  • 42
14

Some people have asked: how can the singleton return a null pointer? I'm answering that question. (I cannot answer in a comment because I need to post code.)

It may return null in between two events: (1) the class is loaded, and (2) the object of this class is created. Here's an example:

class X {
    static X xinstance;
    static Y yinstance = Y.yinstance;
    X() {xinstance=this;}
}
class Y {
    static X xinstance = X.xinstance;
    static Y yinstance;
    Y() {yinstance=this;}
}

public class A {
    public static void main(String[] p) {
    X x = new X();
    Y y = new Y();
    System.out.println("x:"+X.xinstance+" y:"+Y.yinstance);
    System.out.println("x:"+Y.xinstance+" y:"+X.yinstance);
    }
}

Let's run the code:

$ javac A.java 
$ java A
x:X@a63599 y:Y@9036e
x:null y:null

The second line shows that Y.xinstance and X.yinstance are null; they are null because the variables X.xinstance ans Y.yinstance were read when they were null.

Can this be fixed? Yes,

class X {
    static Y y = Y.getInstance();
    static X theinstance;
    static X getInstance() {if(theinstance==null) {theinstance = new X();} return theinstance;}
}
class Y {
    static X x = X.getInstance();
    static Y theinstance;
    static Y getInstance() {if(theinstance==null) {theinstance = new Y();} return theinstance;}
}

public class A {
    public static void main(String[] p) {
    System.out.println("x:"+X.getInstance()+" y:"+Y.getInstance());
    System.out.println("x:"+Y.x+" y:"+X.y);
    }
}

and this code shows no anomaly:

$ javac A.java 
$ java A
x:X@1c059f6 y:Y@152506e
x:X@1c059f6 y:Y@152506e

BUT this is not an option for the Android Application object: the programmer does not control the time when it is created.

Once again: the difference between the first example and the second one is that the second example creates an instance if the static pointer is null. But a programmer cannot create the Android application object before the system decides to do it.

UPDATE

One more puzzling example where initialized static fields happen to be null.

Main.java:

enum MyEnum {
    FIRST,SECOND;
    private static String prefix="<", suffix=">";
    String myName;
    MyEnum() {
        myName = makeMyName();
    }
    String makeMyName() {
        return prefix + name() + suffix;
    }
    String getMyName() {
        return myName;
    }
}
public class Main {
    public static void main(String args[]) {
        System.out.println("first: "+MyEnum.FIRST+" second: "+MyEnum.SECOND);
        System.out.println("first: "+MyEnum.FIRST.makeMyName()+" second: "+MyEnum.SECOND.makeMyName());
        System.out.println("first: "+MyEnum.FIRST.getMyName()+" second: "+MyEnum.SECOND.getMyName());
    }
}

And you get:

$ javac Main.java
$ java Main
first: FIRST second: SECOND
first: <FIRST> second: <SECOND>
first: nullFIRSTnull second: nullSECONDnull

Note that you cannot move the static variable declaration one line upper, the code will not compile.

18446744073709551615
  • 16,368
  • 4
  • 94
  • 127
  • 3
    Useful example; its good to know that there is such a hole. What I take away from this is that one should avoid referring to such a static variable during static initialization of any class. – ToolmakerSteve May 03 '15 at 14:01
11

Application Class:

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

public class MyApplication extends Application {

    private static Context mContext;

    public void onCreate() {
        super.onCreate();
        mContext = getApplicationContext();
    }

    public static Context getAppContext() {
        return mContext;
    }

}

Declare the Application in the AndroidManifest:

<application android:name=".MyApplication"
    ...
/>

Usage:

MyApplication.getAppContext()
toha
  • 5,095
  • 4
  • 40
  • 52
9

You are trying to create a wrapper to get Application Context and there is a possibility that it might return "null" pointer.

As per my understanding, I guess its better approach to call- any of the 2 Context.getApplicationContext() or Activity.getApplication().

machei
  • 337
  • 2
  • 16
Prasanta
  • 279
  • 4
  • 2
5

It is a good approach. I use it myself as well. I would only suggest to override onCreate to set the singleton instead of using a constructor.

And since you mentioned SQLiteOpenHelper: In onCreate () you can open the database as well.

Personally I think the documentation got it wrong in saying that There is normally no need to subclass Application. I think the opposite is true: You should always subclass Application.

Martin
  • 11,577
  • 16
  • 80
  • 110
3

I would use Application Context to get a System Service in the constructor. This eases testing & benefits from composition

public class MyActivity extends Activity {

    private final NotificationManager notificationManager;

    public MyActivity() {
       this(MyApp.getContext().getSystemService(NOTIFICATION_SERVICE));
    }

    public MyActivity(NotificationManager notificationManager) {
       this.notificationManager = notificationManager;
    }

    // onCreate etc

}

Test class would then use the overloaded constructor.

Android would use the default constructor.

Blundell
  • 75,855
  • 30
  • 208
  • 233
1

I like it, but I would suggest a singleton instead:

package com.mobidrone;

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

public class ApplicationContext extends Application
{
    private static ApplicationContext instance = null;

    private ApplicationContext()
    {
        instance = this;
    }

    public static Context getInstance()
    {
        if (null == instance)
        {
            instance = new ApplicationContext();
        }

        return instance;
    }
}
CoolBeans
  • 20,654
  • 10
  • 86
  • 101
  • 32
    Extending android.app.application already guarantees singleton so this is unnecessary – Vincent Apr 15 '11 at 08:21
  • 8
    What if you want acess from non activity classes? – Maxrunner Sep 21 '11 at 14:00
  • 9
    You should never `new` the Application yourself (with the possible exception of unit testing). The operating system will do that. You should also not have an constructor. That is what `onCreate` is for. – Martin Aug 07 '13 at 12:37
  • @Vincent: can you post some link on this ? preferably code - I am asking here : http://stackoverflow.com/questions/19365797/androids-basic-components-class-loading-java-objects-lifecycle – Mr_and_Mrs_D Nov 04 '13 at 14:15
  • @radzio why we shouldn't do it in constructor? – Miha_x64 Jan 22 '17 at 16:14
  • @Martin in Java, there's no way to have no constructor in a class. If there are no explicit constructors, javac generates a publuc no-arg one. – Miha_x64 Jan 22 '17 at 16:14
  • Well that's what I said: Don't declare an explicit constructor use onCreate itself because at onCreate the class usable. – Martin Jan 22 '17 at 17:06
0

I'm using the same approach, I suggest to write the singleton a little better:

public static MyApp getInstance() {

    if (instance == null) {
        synchronized (MyApp.class) {
            if (instance == null) {
                instance = new MyApp ();
            }
        }
    }

    return instance;
}

but I'm not using everywhere, I use getContext() and getApplicationContext() where I can do it!

Seraphim's
  • 12,559
  • 20
  • 88
  • 129
  • So, please write a comment to explain why you've downvoted the answer so I can understand. The singleton approach is widely used to get a valid context outside activities or views body... – Seraphim's Jul 17 '13 at 08:15
  • 1
    No need as the operating system ensures that the Application is instantiated exactly once. If any I would suggest to set the Singelton in onCreate (). – Martin Aug 07 '13 at 12:35
  • 1
    A good thread-safe way to lazy initialize a singleton, but not neccessary here. – naXa stands with Ukraine Apr 13 '14 at 23:39
  • 3
    Wow, just when I thought people had finally stopped using double-checked locking... http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html – Søren Boisen Jan 12 '16 at 16:26
0

I know the original question was posted 13 years ago, and this is the Kotlin version of getting context everywhere.

class MyApplication : Application() {
    companion object {
        @JvmStatic
        private var instance: MyApplication? = null

        @JvmStatic
        public final fun getContext(): Context? {
            return instance
        }
    }

    override fun onCreate() {
        instance = this
        super.onCreate()
    }
}
Stanley Ko
  • 3,383
  • 3
  • 34
  • 60