As a general rule, an Android context should be stored as little as possible and used only when needed.
If you're getting null or invalid exceptions when trying to use the Activity context, that means you're performing operations outside the standard Android lifecycle of an Activity.
Due to the nature of the lifecycle (asynchronous), it's sometimes really hard to predict when these situations will arise… unless, you avoid performing operations outside the lifecycle events where the context is guaranteed to be alive.
E.g.: Performing Activity/Context operations in onPostExecute
methods of asynctasks or even threads, is a time bomb.
As a general rule, before attempting to use an Activity/Context outside the lifecycle methods (onResume for example), is also dangerous and should always be accompanied by a null check.
I used to have a simple method to check this:
if (activity != null && !activity.isFinishing()) {
// safe
}
After Jelly Bean (API 17 afaik) you can also check activity.isDestroyed()
or similar (can't remember now).
If you have to store a context (to later perform some context related action), always try to store the Application Context (activity.getApplicationContext()) which is a static reference to the Application
singleton and it won't leak.
That being said, keep in mind what limitations each type of context has. When in doubt, keep a bookmark to this around, specially to understand why trying to inflate layouts with an Application context may yield unexpected results.
UPDATE:
If you need a common/generic place to operate on your Fragments, keep a handy util class around like (pseudo code):
public final class FragmentUtils {
private FragmentUtils() {
}
public static void add(FragmentActivity fragmentActivity, int layoutId, Fragment fragment) {
if (isContextInvalid(fragmentActivity)) {
return
}
FragmentTransaction fragmentTransaction = fragmentActivity.getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(layoutId, fragment);
fragmentTransaction.commit();
}
public static void replace(FragmentActivity fragmentActivity, int layoutId, Fragment fragment) {
if (isContextInvalid(fragmentActivity)) {
return
}
// TODO: you do this one ;)
}
public static void remove(FragmentActivity fragmentActivity, Fragment fragment) {
if (isContextInvalid(fragmentActivity)) {
return
}
// TODO: you do this one ;)
if (fragment.isAdded()) {
…
}
}
public static void show(FragmentActivity fragmentActivity, Fragment fragment) {
// TODO: you do this one ;)
if (fragment.isAdded()) {
…
}
}
public static void hide(FragmentActivity fragmentActivity, Fragment fragment) {
// TODO: you do this one ;)
if (fragment.isAdded()) {
…
}
}
public boolean isContextInvalid(final Context context) {
if (context == null || context.isFinishing()) {
return true;
}
return false;
}
}
And add the null/checks to your context there. (Or similar)
Note the above code is not complete, I just wrote it here in this editor….