What's the difference between the various methods to get an Android Context?
Asked Answered
B

7

403

In various bits of Android code I've seen:

 public class MyActivity extends Activity {
    public void method() {
       mContext = this;    // since Activity extends Context
       mContext = getApplicationContext();
       mContext = getBaseContext();
    }
 }

However I can't find any decent explanation of which is preferable, and under what circumstances which should be used.

Pointers to documentation on this, and guidance about what might break if the wrong one is chosen, would be much appreciated.

Banky answered 22/6, 2009 at 12:38 Comment(1)
This link might help you. Go through this..Kyleekylen
P
313

I agree that documentation is sparse when it comes to Contexts in Android, but you can piece together a few facts from various sources.

This blog post on the official Google Android developers blog was written mostly to help address memory leaks, but provides some good information about contexts as well:

In a regular Android application, you usually have two kinds of Context, Activity and Application.

Reading the article a little bit further tells about the difference between the two and when you might want to consider using the application Context (Activity.getApplicationContext()) rather than using the Activity context this). Basically the Application context is associated with the Application and will always be the same throughout the life cycle of your app, where as the Activity context is associated with the activity and could possibly be destroyed many times as the activity is destroyed during screen orientation changes and such.

I couldn't find really anything about when to use getBaseContext() other than a post from Dianne Hackborn, one of the Google engineers working on the Android SDK:

Don't use getBaseContext(), just use the Context you have.

That was from a post on the android-developers newsgroup, you may want to consider asking your question there as well, because a handful of the people working on Android actual monitor that newsgroup and answer questions.

So overall it seems preferable to use the global application context when possible.

Prato answered 22/6, 2009 at 14:11 Comment(3)
When I have an activity A which can start activity B which, in turn, can restart A with CLEAR_TOP flag (and possibly repeat this cycle many times) - what context should I use in this case in order to avoid building up a huge trail of referenced contexts? Diana says using 'this' rather than getBaseContext, but then... most of the times A will be reused but there are situations when a new object for A will be created and then the old A leaks. So it seems that getBaseContext is the most proper choice for most cases. Then it's not clear why Don't use getBaseContext(). Could someone clarify this?Angleaangler
how would one access the context object inside of a class that does not extend Activity?Tampon
@Cole, you could create a class, which we'll call "ExampleClass" here, whose constructor takes a Context object and instantiates a class instance variable, "appContext". Then, your Activity class (or any other Class for that matter) can call an ExampleClass method that makes use of the ExampleClass' "appContext" instance variable.Sanjak
S
58

Here's what I've found regarding the use of context:

1) . Within an Activity itself, use this for inflating layouts and menus, register context menus, instantiating widgets, start other activities, create new Intent within an Activity, instantiating preferences, or other methods available in an Activity.

Inflate layout:

View mView = this.getLayoutInflater().inflate(R.layout.myLayout, myViewGroup);

Inflate menu:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);
    this.getMenuInflater().inflate(R.menu.mymenu, menu);
    return true;
}

Register context menu:

this.registerForContextMenu(myView);

Instantiate widget:

TextView myTextView = (TextView) this.findViewById(R.id.myTextView);

Start an Activity:

Intent mIntent = new Intent(this, MyActivity.class);
this.startActivity(mIntent);

Instantiate preferences:

SharedPreferences mSharedPreferences = this.getPreferenceManager().getSharedPreferences();

2) . For application-wide class, use getApplicationContext() as this context exist for the lifespan of the application.

Retrieve the name of the current Android package:

public class MyApplication extends Application {    
    public static String getPackageName() {
        String packageName = null;
        try {
            PackageInfo mPackageInfo = getApplicationContext().getPackageManager().getPackageInfo(getApplicationContext().getPackageName(), 0);
            packageName = mPackageInfo.packageName;
        } catch (NameNotFoundException e) {
            // Log error here.
        }
        return packageName;
    }
}

Bind an application-wide class:

Intent mIntent = new Intent(this, MyPersistent.class);
MyServiceConnection mServiceConnection = new MyServiceConnection();
if (mServiceConnection != null) {
    getApplicationContext().bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
}

3) . For Listeners and other type of Android classes (e.g. ContentObserver), use a Context substitution like:

mContext = this;    // Example 1
mContext = context; // Example 2

where this or context is the context of a class (Activity, etc).

Activity context substitution:

public class MyActivity extends Activity {
    private Context mContext;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);        
        mContext = this;
    }
}

Listener context substitution:

public class MyLocationListener implements LocationListener {
    private Context mContext;
    public MyLocationListener(Context context) {
        mContext = context;
    }
}

ContentObserver context substitution:

public class MyContentObserver extends ContentObserver {
    private Context mContext;
    public MyContentObserver(Handler handler, Context context) {
        super(handler);
        mContext = context;
    }
}

4) . For BroadcastReceiver (including inlined/embedded receiver), use the receiver's own context.

External BroadcastReceiver:

public class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        final String action = intent.getAction();
        if (action.equals(Intent.ACTION_SCREEN_OFF)) {
            sendReceiverAction(context, true);
        }
        private static void sendReceiverAction(Context context, boolean state) {
            Intent mIntent = new Intent(context.getClass().getName() + "." + context.getString(R.string.receiver_action));
            mIntent.putExtra("extra", state);
            context.sendBroadcast(mIntent, null);
        }
    }
}

Inlined/Embedded BroadcastReceiver:

public class MyActivity extends Activity {
    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final boolean connected = intent.getBooleanExtra(context.getString(R.string.connected), false);
            if (connected) {
                // Do something.
            }
        }
    };
}

5) . For Services, use the service's own context.

public class MyService extends Service {
    private BroadcastReceiver mBroadcastReceiver;
    @Override
    public void onCreate() {
        super.onCreate();
        registerReceiver();
    }
    private void registerReceiver() {
        IntentFilter mIntentFilter = new IntentFilter();
        mIntentFilter.addAction(Intent.ACTION_SCREEN_OFF);
        this.mBroadcastReceiver = new MyBroadcastReceiver();
        this.registerReceiver(this.mBroadcastReceiver, mIntentFilter);
    } 
}

6) . For Toasts, generally use getApplicationContext(), but where possible, use the context passed from an Activity, Service, etc.

Use context of the application:

Toast mToast = Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG);
mToast.show();

Use context passed from a source:

public static void showLongToast(Context context, String message) {
    if (context != null && message != null) {
        Toast mToast = Toast.makeText(context, message, Toast.LENGTH_LONG);
        mToast.show();
    }
}

And last, don't use getBaseContext() as advised by Android's framework developers.

UPDATE: Add examples of Context usage.

Senega answered 19/12, 2012 at 4:43 Comment(2)
Instead of mContext one can use OuterClass.this ; see comments in #9605959Greathearted
+1 for such a helpful answer! I agree that the accepted answer is fine as accepted answer, but holy molly this answer was super informative! Thank you for all those examples, they helped me to better understand the context usage as a whole. I even copied your answer into a text file on my machine as a reference.Accidental
D
13

I read this thread a few days ago, asking myself the same question. My decision after reading this was simple: always use applicationContext.

However, I encountered a problem with this, I spent a few hours to find it, and a few seconds to solve it... (changing one word...)

I am using a LayoutInflater to inflate a view containing a Spinner.

So here are two possibilities:

1)

    LayoutInflater layoutInflater = LayoutInflater.from(this.getApplicationContext());

2)

    LayoutInflater layoutInflater = LayoutInflater.from(this.getBaseContext());

Then, I am doing something like this:

    // managing views part
    View view = ContactViewer.mLayoutInflater.inflate(R.layout.aViewContainingASpinner, theParentView, false);
    Spinner spinner = (Spinner) view.findViewById(R.id.theSpinnerId);
    String[] myStringArray = new String[] {"sweet","love"};

    // managing adapter part
    // The context used here don't have any importance -- both work.
    ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this.getApplicationContext(), myStringArray, android.R.layout.simple_spinner_item);
    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    spinner.setAdapter(adapter);

    theParentView.addView(view);

What I noticed: If you instantiated your linearLayout with the applicationContext, then when you click on the spinner in your activity, you will have an uncaught exception, coming from the dalvik virtual machine (not from your code, that's why I have spent a lot of time to find where was my mistake...).

If you use the baseContext, then that's all right, the context menu will open and you will be able to choose among your choices.

So here is my conclusion: I suppose (I have not tested it further) than the baseContext is required when dealing with contextMenu in your Activity...

The test has been done coding with API 8, and tested on an HTC Desire, android 2.3.3.

I hope my comment have not bored you so far, and wish you all the best. Happy coding ;-)

Duty answered 6/1, 2012 at 17:14 Comment(1)
I've always used "this" when creating views in an activity. On the basis that if the activity restarts, the views are remade and there maybe a new context which to use to make the views from again. The drawback as posted in the developer blog is whilst an ImageView is destoryed the drawable/bitmap used may hang onto that context. Nevertheless that's what I do at the moment. Regarding code elsewhere in the app (normal classes) I just use application context as its not specific to any activity or UI elements.Elburr
O
6

First, I agree that we should use appcontext whenever possible. then "this" in activity. i've never had a need for basecontext.

In my tests, in most cases they can be interchanged. In most cases, the reason you want to get a hold of a context is to access files, preferences, database etc. These data is eventually reflected as files in your app's private data folder (/data/data/). No matter which context you use, they'll be mapped to the same folder/files so you are OK.

That's what I observed. Maybe there are cases you should distinguish them.

Overbite answered 20/3, 2010 at 8:48 Comment(1)
I've needed basecontext to globally set the app language on startup (when it does not match that of the phone default lang).Cowan
L
3

In some cases you may use Activity context over application context when running something in a thread. When thread completes execution and you need to return the result back to the caller activity, you need that context with a handler.

((YourActivity) context).yourCallbackMethod(yourResultFromThread, ...);
Lapith answered 24/9, 2010 at 23:29 Comment(0)
U
2

In simple words

getApplicationContext() as the method name suggest will make your app aware of application wide details which you can access from anywhere in the app. So you can make use of this in service binding, broadcast registration etc. Application context will be alive till the app exits.

getActivity() or this will make your app aware of the current screen which is visible also the app level details provided by application context. So whatever you want to know about the current screen like Window ActionBar Fragementmanger and so are available with this context. Basically and Activity extend Context. This context will alive till the current component(activity) is alive

Ulcerous answered 9/2, 2017 at 12:49 Comment(0)
M
0

I've only used this and getBaseContext when toasting from an onClick (very green noob to both Java and android). I use this when my clicker is directly in the activity and have to use getBaseContext in an anonymous inner clicker. I'm guessing that is pretty much the trick with getBaseContext, it is perhaps returning the context of the activity in which the inner class is hiding.

Mollee answered 12/12, 2011 at 17:2 Comment(1)
This is wrong, it is returning the base context of the activity itself. To get the activity (the one you want to use as context) from an anonymous inner class use something like MyActivity.this. Using the base context as you describe will probably not cause problems but it is wrong.Gwenn

© 2022 - 2024 — McMap. All rights reserved.