Static way to get 'Context' in Android?
Asked Answered
C

21

1106

Is there a way to get the current Context instance inside a static method?

I'm looking for that way because I hate saving the 'Context' instance each time it changes.

Canterbury answered 4/1, 2010 at 21:15 Comment(9)
Not saving Context is a good idea not just because it is inconvenient, but more because it can lead to huge memory leaks!Preciado
@VikramBodicherla Yes, but the answers below assume that we are talking about the application context. So, memory leaks are not an issue, but the user should only use these solutions where that is the correct context to use.Flounder
If you have to use a static way of getting Context, then there might be a better way to design the code.Isolationist
Android documentation recommends passing the context to getters of singletons. developer.android.com/reference/android/app/Application.htmlIronmonger
For preferring singletons and context passed with getInstance() over static context, please have a look, I tried to explain my reasoning here supported with working code: https://mcmap.net/q/14521/-static-way-to-get-39-context-39-in-androidRudder
If you're looking at needing static context you should consider that maybe you have a design problem. Check Factory design patterns and like @VikramBodicherla said, huge memory leaks!Codger
@Flounder What other types of context would be a problem here? Seems the Application context is not a problem. What types are then?Vardar
Context and ApplicationContext are the same, but one of them is themed. Whenever static code requires Context, better ignore these so called "solutions" and ask yourself how to properly pass it.Rios
I wonder if SO should be a place to search for discussions or to find a solution to problem, because to find the solution for this question you must go through 21 Answers.Burnley
R
1414

Do this:

In the Android Manifest file, declare the following.

<application android:name="com.xyz.MyApplication">

</application>

Then write the class:

public class MyApplication extends Application {

    private static Context context;

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

    public static Context getAppContext() {
        return MyApplication.context;
    }
}

Now everywhere call MyApplication.getAppContext() to get your application context statically.

Realgar answered 25/2, 2011 at 6:37 Comment(26)
Is there any downside to this method? This seems like cheating. (A hack?)Natalienatalina
Also maybe.. should we declare this static context variable as volatile?Podiatry
@VladimirSorokin: no volatile keyword is needed as the context referes always to the same object. The value of the pointer could be made final as it never changes once assigned.Barri
@RaphMclee: You can not make it final because it's initialized not in c-tor. Still the context variable may be accessed by multiple threads. And according to "Java Concurrency In Practice - 3.5.3. Safe Publication Idioms": to publish a reference safly you should use one of the following approaches: static initializer, volatile field, AtomicReference, final field, lock. Otherwise you might have problems with concurrency. But I'm not 100% sure about our particular case, there are different subtle nuances, so I decided to use volatile just in case, it doesn't affect performance anyway.Podiatry
Does anybody know the reasoning for setting the context variable in onCreate() instead of in a constructor?Karyoplasm
@Karyoplasm probably because it doesnt exist before ? You might get nullo.Steviestevy
@MelindaGreen I disagree. Where you have static attributes that are initialized with a static, then you already know that you are doing something that depends on order of initialization and need to be careful. Mostly, you just won't use this in that way.Flounder
@nerith Create a 'surrogate' class in your common library code and then set Surrogate.context from App.onCreate(). I also do this for BuildConfig.DEBUG flag since it is not accessible from library code.Flounder
@Flounder This is not a case of a static data member being initially statically. In the given code, the static member is being initialized non-statically in onCreate(). Even statically initialized data is not good enough in this case because nothing insures that the static initialization of the given class will happen before it will be accessed during the static initialization of some other class.Subscribe
@MelindaGreen I agree with the statement you just made. For the reason you stated I simply would not reference getApplicationContext in a static initializer. The OP wants a way to access the context via a static method, but I do not interpret that to mean that he wants to be able to use that static method in a static initializer.Flounder
@Flounder Again, this not about static initialization but initialization order in general. The proposed solution simply sets up a race condition. If it generally seems to work, that just seems like good luck (I.E bad luck). And that's the downside that I described in my first comment which is that to be safe, callers would need to be ready to get null values. Unfortunately, that seems like the problem the OP was trying to solve. Depending upon the situation, perhaps the OP didn't realize that Activities and Services are Contexts and might have had no problem to begin with.Subscribe
@MelindaGreen According to the documentation for Application, onCreate() is called before any activity, service or receiver (excluding content providers) have been created. So wouldn't this solution be safe as long as you're not trying to access getAppContext() from a content provider?Schizogony
@BadCash I think in a way, it is "safe", because the framework guarantees onCreate will get called for each Activity, and by that time, the application context will also already be created. However, from a maintenance point-of-view, there are a few caveats you have to be aware of, and that is, you have to be prepared to get null values depending on where you call this function from. (ie. if you call it from a constructor, the context static variable may not have been initialized yet.) So, you should always check for null, just to be sure. Personally, I would not do it this way.Evaporate
@BadCash, thanks for pointing out the documentation. It says up front that there's generally no need to subclass from Application because singletons are probably better. It then says that to implement such a singleton, your function to get the instance should pass in its Context on which your singleton initialization calls getApplicationContext(). That way the first call will cause the singleton to be set and callers won't have to worry about getting nulls. Unfortunately that means that they have to have a Context, which was the original problem. Erich's answer below is the correct one.Subscribe
Will onCreate method be called when app is invoked with android.intent.action.BOOT_COMPLETED broadcast? it seems that was the root of my problems. I was expecting that onCreate to be invoked but for some reason that does not seem to be the case. When using solution of yours one should be careful in some cases.Nicotinism
@TeeTracker In this case, there won't be a leak because the Application object is alive for as long as the app itself is alive, i.e. it doesn't get garbage collected during the lifetime of the app.Dextrogyrate
There are clear cases when an application has a content provider in which the content provider is initialized before the application object and therefore you cannot count on the static field to be initialized in this case.Sadoc
So long as you aren't initializing classes that will statically try to reference the statically stored context, doing this in a subclass of Application (which is defined as THE application in AndroidManifest.xml, is safe, because the Android system guarantees that your application instance .onCreate will be the very first thing called before anything else. So, while not a "safe" way to do this in normal java, this would be like setting a static field in a regular java main... Safe, so long as you aren't doing god-awful static things with other static initialized fields.Pique
This solution triggers an Android Lint Performance warning, since Android Contexts placed in static fields constitutes a memory leak... You can check it out for yourself, in Android Studio: Analyze>Inspect Code...Stolen
It's upsetting to see how many upvotes this answer has. You should never hold a static instance to context - for proofs sake, try using Leak Canary (github.com/square/leakcanary) and find the memory leak caused because of this. @people-with-enouhg-rep-and-Android-knowledge, please re-review this answer and act accordingly. This is guaranteed to be used by beginners and it's plain simple wrong.Anima
@cyrilchampier I made a library that works with libraries: github.com/LouisCAD/Splitties/blob/master/appctx/README.md It uses a dummy ContentProvider to get a safe ContextXmas
In the modern spirit of "things that should be easy should be easy", there should really be a Context.getApplicationContext() or Application.getApplicationContext() static method. This object is a singleton and should be accessible as such without jumping through hoops. Until that is addressed, outside of a static initializer or a content provider, i.e. in 99% of my code, this answer provides a reasonable workaround. Thanks to the commenters who pointed out those specific cases where this technique is not safe.Essentialism
@CrearoRotar It ain't wrong actually, storing static reference to application context is not at all a bad practice in my opinion, there won't be any memory leaks because the android system would already have killed your process, although I agree that it should be used with care.Mohave
@MelindaGreen - re "Unfortunately that means that they have to have a Context, which was the original problem." Yes and no. To avoid null, it is necessary to first run some code that has some Context - so there is no truly universal solution, as Erich says and you mention. OTOH, it might be possible to order one's code such that some Context exists "early enough". If so, then whatever Context that is, should call myContext.getApplicationContext, and store that into this static global. Do you know whether there is ever any context prior to Application.onCreate?Reeba
@ToolmakerSteve, No, I don't know, but I suggest you don't count on it unless the documentation explicitly says you can.Subscribe
Caution : is some rare cases, this block of code will not be called and that can cause a NPE crash : when app data is restored from the cloud, Application.onCreate() is not called at next start. https://mcmap.net/q/14820/-android-application-instance-is-cleared-as-nullJustis
W
117

The majority of apps that want a convenient method to get the application context create their own class which extends android.app.Application.

GUIDE

You can accomplish this by first creating a class in your project like the following:

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

public class App extends Application {

    private static Application sApplication;

    public static Application getApplication() {
        return sApplication;
    }

    public static Context getContext() {
        return getApplication().getApplicationContext();
    }

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

Then, in your AndroidManifest you should specify the name of your class in the AndroidManifest.xml’s tag:

<application 
    ...
    android:name="com.example.App" >
    ...
</application>

You can then retrieve the application context in any static method using the following:

public static void someMethod() {
    Context context = App.getContext();
}

WARNING

Before adding something like the above to your project you should consider what the documentation says:

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.


REFLECTION

There is also another way to get the application context using reflection. Reflection is often looked down upon in Android and I personally think this should not be used in production.

To retrieve the application context we must invoke a method on a hidden class (ActivityThread) which has been available since API 1:

public static Application getApplicationUsingReflection() throws Exception {
    return (Application) Class.forName("android.app.ActivityThread")
            .getMethod("currentApplication").invoke(null, (Object[]) null);
}

There is one more hidden class (AppGlobals) which provides a way to get the application context in a static way. It gets the context using ActivityThread so there really is no difference between the following method and the one posted above:

public static Application getApplicationUsingReflection() throws Exception {
    return (Application) Class.forName("android.app.AppGlobals")
            .getMethod("getInitialApplication").invoke(null, (Object[]) null);
} 

Happy coding!

Wednesday answered 19/1, 2015 at 9:9 Comment(2)
Yep! Love the last approach! Especially because I've internal/hidden APIs showing on Android Studio, so I don't even need to use Reflection, which seems safer (if the methods disappear, Android Studio will warn about it). Wonder why this is not on the SDK. Makes life easier, I think.Vardar
I just found a problem with the last approach... Doesn't seem to always return the context. getApplicationContext() and getBaseContext() work, but when I call ActivityThread.currentApplication(), it returns null. I'm calling all 3 inside a Thread which is declared inside a Service as a constant. Might not be a reliable way of getting a Context instance. Though I don't think it happened many times since my other comment. I think this is the only time. It's happening on Android 4.0.3 on the emulator, but doesn't happen with OnePlus X on Lollipop 5.1 nor on BV9500 with Oreo 8.1.Vardar
R
68

Assuming we're talking about getting the Application Context, I implemented it as suggested by @Rohit Ghatol extending Application. What happened then, it's that there's no guarantee that the context retrieved in such a way will always be non-null. At the time you need it, it's usually because you want to initialize an helper, or get a resource, that you cannot delay in time; handling the null case will not help you. So I understood I was basically fighting against the Android architecture, as stated in the docs

Note: There is normally no need to subclass Application. In most situations, 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), include Context.getApplicationContext() as a Context argument when invoking your singleton's getInstance() method.

and explained by Dianne Hackborn

The only reason Application exists as something you can derive from is because during the pre-1.0 development one of our application developers was continually bugging me about needing to have a top-level application object they can derive from so they could have a more "normal" to them application model, and I eventually gave in. I will forever regret giving in on that one. :)

She is also suggesting the solution to this problem:

If what you want is some global state that can be shared across different parts of your app, use a singleton. [...] And this leads more naturally to how you should be managing these things -- initializing them on demand.

so what I did was getting rid of extending Application, and pass the context directly to the singleton helper's getInstance(), while saving a reference to the application context in the private constructor:

private static MyHelper instance;
private final Context mContext;    

private MyHelper(@NonNull Context context) {
    mContext = context.getApplicationContext();
}

public static MyHelper getInstance(@NonNull Context context) {
    synchronized(MyHelper.class) {
        if (instance == null) {
            instance = new MyHelper(context);
        }
        return instance;
    }
}

the caller will then pass a local context to the helper:

Helper.getInstance(myCtx).doSomething();

So, to answer this question properly: there are ways to access the Application Context statically, but they all should be discouraged, and you should prefer passing a local context to the singleton's getInstance().


For anyone interested, you can read a more detailed version at fwd blog

Rudder answered 16/8, 2016 at 5:36 Comment(24)
Note that in Android Studio (2.3.1, at least) you a warning to not save the context in a static field when you do this (memory leak). Is that actually correct in this case? I got rid of it by getting everything I needed from the context and save that (file paths and so on) in members, so I am fine, just clarifying. Also this approach seems a bit weird at first because you don't do anything with the context on subsequent calls of getInstance(). :) Still, the answer convinced me more than the accepted one.Frannie
@Frannie I save the application context reference because I assume some other method of MyHelper will need it. If you don't need it ever, then you shouldn't keep a reference of it (for what for?). Also, your approach doesn't allow resource changes (for instance when user switch language), so I wouldn't recommend it. Last but not least, lint warning is correct because what lint see is a Context, but in this case I take the application context ("the context of the single, global Application object of the current process") on a singleton, which after lazy initialization is available until crashRudder
@Rudder Yup, in my case I don't accommodate for ressource changes, but that is fine for me, in my app's context. I also, in the end, did indeed remove a reference to the context (after realizing I can simply live with the data I got from it on initialization). So I meant to say "Thus, in my case it's a bit weird to keep on handing over the context on subsequent calls of getInstance()", sorry if that was unclear. Also, thanks for clarifying that it's fine to ignore the lint warning as long as you just save the application context. I already guessed so, but confirmation is always good.Frannie
@Frannie in your specific case then I'll be even more defensive: instead of passing the context to the constructor or getInstance(), just pass the needed initialization parameters directly, and let the caller to use the context to retrieve them. Then your interface / API is even more clear, because it indicates your class or helper doesn't need the context at all. You're welcome, I'm happy to clarify and also I'm planning to write down an extended entry for this answer, so I have more space to comment and answer any doubt.Rudder
@Rudder Yes, that is probably more useful. I'm not yet done with the class anyway, so that's on my refactoring ToDo. I'm also considering to have a specific setupInstance() method or something for this and have the singelton use some meaningful default behavior if that hasn't been called yet. The downside of that would be that the lazy-initialization isn't very nice with this, as it isn't when you need to pass in useless parameters all the time (that were only used on the first call), whether it's wrapped in the context or individual ones. It's a bummer the instance can't get those by itself.Frannie
@Rudder Great article! This is exactly what I finally did (apart from the multiple threading concept as I don't need that for now). Thanks a lot for going the extra mile and also compiling the various sources about the issue (like Dianne's statement).Frannie
@Rudder Doesn't this method lead to memory leaksIndre
@codephillip no. Why do you think so? Please tell me more, also read my blog entry for more details on thisRudder
@Rudder its a singleton taking in the context from the component(activity). What happens when the component is killed by the system. What happens when onResume(), onStart() are called. You should test the app by opening several other applications on your phone then returning after like 5-10 minutes, you may find that your app has crashed because the singleton is referencing a context from a killed component(activity)Indre
@codephillip I don't understand what you're talking about. The singleton references the application context retrieved from the passed activity, not the host activity. That's legit, and it will not cause any memory leak. That's the main point of the blog I wrote. If you really think you're right, please send me a sample code where I can reproduce the memory leak you're talking about, because that's not the case.Rudder
I think @KigenyiPhillip is correct, and this does still represent a resource leak. Picture the reference chart after your first call to getInstance(ctx). You have a GC root instance of type MyHelper, which has a private field mContext of type Context, which references the application context collected via the context passed to getInstance(). instance is never set a second time, nor cleared, so GC will never catch the appcontext referenced by instance. You don't leak any activities so it's low cost IMO.Spiny
@MarkMcKenna as you state "which has a private field mContext of type Context, which references the application context", so that's clear to you that mContext is a reference to the application context, not to any context. In getApplicationContext() docs you read: "a Context whose lifecycle is separate from the current context, that is tied to the lifetime of the process rather than the current component". How can this create a memory leak? The application context is GC'd only when the process exits.Rudder
@Rudder if you accept that a reference to the application context doesn't qualify as a resource leak, then you can simplify this by posting a static reference to this in Application.onCreate(), which makes the accepted answer better.Spiny
@MarkMcKenna first you say it's a leak, now you're saying is not. A reference to the application context is not a leak. But the problem of the accepted answer (to extend Application and retrieve the context statically) is not in leaking resources, but retrieving a static context which could be 'null', and at that point you can't do much with it. I explained this in more details in our blog, please read it through carefully. After that, if you've any concern, let me know. Also read Dianne words very carefully, if not mine.Rudder
@Rudder I've looked at your blog, but I don't understand one thing: you got a null when using the app-subclass technique, so you were running code before app onCreate: what Context did you have access to in such code, to pass to the helper? As an aside, Mark McKenna is partially correct: it makes no difference whether you use a separate singleton class, as you do, or whether this technique is used while subclassing Application - so you could have omitted all that discussion; the essence is that you start from some context, to avoid null. Good point re not caching the non-app context.Reeba
@Reeba I don't understand your question, but basically what I experienced was that some statically loaded classes could retrieve from app-subclass technique a reference containing null, that simple. My main point is not about not subclassing application, but instead is not to retrieve the context statically. It should be retrieved on demand, passing it around from parents to children every single time. Bear with me: every single time. And it's not me explaining this, even if it seems to me it's not understood yet, it's Dianne Hackborn herself, and there's no doubts about her words.Rudder
np. The essence of your answer - "start from a local context" is the important advice here (as Erich Douglass' answer said years ago). CLARIFICATION FOR OTHERS: the singleton is only needed when accessing your own custom globals. The original question was about accessing the application context anywhere. If someone is trying to do that, this doesn't help them do so - since you require a Context parameter myCtx. To merely access app context, this singleton is not needed - coder should simply do myCtx.getApplicationContext()....Reeba
@Reeba I showed the example as a singleton, because that's how it's explained in the Android docs I reference: "Note: There is normally no need to subclass Application. In most situations, 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), include Context.getApplicationContext() as a Context argument when invoking your singleton's getInstance() method.". So I showed exactly how you would do that, to pass it in getInstance() and retrieve the application context from it.Rudder
@Reeba so I disagree with what you say "If someone is trying to do that, this doesn't help them do so - since you require a Context parameter". Yes it does. It's simple: you shouldn't access your context everywhere, but you should pass it from parents to children all around, and children keep from it references of the application context. That's the proper way, anything else is purely wrong. I'm surprised after so many years this is not understood yet, and not because of me but because of Hackborn words and design of Android system.Rudder
@Reeba if you look at Flutter, which was designed 2 years ago, it uses the same pattern, passing the context on demand. So, there's no way you can fight the system, without been wrong (aka potential npe). And this is to access the global context: if you exclude activities and services classes, which other classes do you have that are not instantiated from an activity? I had only singletons or classes with pure static methods, I can't think of anything else. Do you?Rudder
@Reeba also let me state the obvious and make sure we're on the same page: I'm not suggesting to access the application context via MyHelper singleton. MyHelper is a class which needs to access a context, for instance to retrieve some resources or register a receiver, or whatever, in the doSomething() method. If another helper class AnotherHelper would need something similar, you would also need to pass a context in its getInstance(). And so forth, for all the classes which are not extending a context or have access to a context themselvesRudder
@Rudder - I only commented again to clarify to anyone else coming here, that your answer isn't a solution to the original question, which was seeking a static way to access context. That is what I was referring to when I said "if someone is trying to do that ... this doesn't help them". Your answer is useful for the (different) situation where one has a context available, and wishes to use the app context in static methods. I just want readers to be clear for what purpose your answer is useful - and for what purpose it is not.Reeba
@Reeba I understood perfectly, and I disagree with you big time. I quote myself of few years ago: "So, to answer this question properly: there are ways to access the Application Context statically, but they all should be discouraged, and you should prefer passing a local context to the singleton's getInstance()". My answer answers the question, in such a way that there shouldn't be any way to access the context statically in someone's code, and she should access the context on demand instead. I think you're ignoring what I'm writing, please read it carefully it's all thereRudder
For anyone doubting that using the getInstance singleton pattern + getApplicationContext does not cause a memory leak, check LocalBroadcastManager source code, which does exactly that.Idem
I
51

No, I don't think there is. Unfortunately, you're stuck calling getApplicationContext() from Activity or one of the other subclasses of Context. Also, this question is somewhat related.

Imes answered 5/1, 2010 at 0:46 Comment(1)
The right link to the article: android-developers.blogspot.co.il/2009/01/…Treasury
P
41

Kotlin way:

Manifest:

<application android:name="MyApplication">

</application>

MyApplication.kt

class MyApplication: Application() {

    override fun onCreate() {
        super.onCreate()
        instance = this
    }

    companion object {
        lateinit var instance: MyApplication
            private set
    }
}

You can then access the property via MyApplication.instance

Psychokinesis answered 23/5, 2018 at 12:42 Comment(0)
V
40

Here is an undocumented way to get an Application (which is a Context) from anywhere in the UI thread. It relies on the hidden static method ActivityThread.currentApplication(). It should work at least on Android 4.x.

try {
    final Class<?> activityThreadClass =
            Class.forName("android.app.ActivityThread");
    final Method method = activityThreadClass.getMethod("currentApplication");
    return (Application) method.invoke(null, (Object[]) null);
} catch (final ClassNotFoundException e) {
    // handle exception
} catch (final NoSuchMethodException e) {
    // handle exception
} catch (final IllegalArgumentException e) {
    // handle exception
} catch (final IllegalAccessException e) {
    // handle exception
} catch (final InvocationTargetException e) {
    // handle exception
}

Note that it is possible for this method to return null, e.g. when you call the method outside of the UI thread, or the application is not bound to the thread.

It is still better to use @RohitGhatol's solution if you can change the Application code.

Venuti answered 19/9, 2012 at 13:34 Comment(3)
I used the above method KennyTM, but sometimes the method returns null. Is there some other alternative to this ? Like if we get a null here, we can retrieve the context from elsewhere. In my case, onCreate() of Application is not called. But the above method gets called before it. Plzzz helpCordilleras
This will not always work in the case where GC cleaned out all activity related stuff.Nylanylghau
Then how do getApplicationContext() or getBaseContext() return a Context instance? Static variable internally and they just return it instead of relying on currentApplication()? Would be cool to go get the Context from where the 2 functions get it - but statically. I thought currentApplication() was where the other 2 would go, but it seems not to be. Wonder what is it then.Vardar
C
33

It depends on what you are using the context for. I can think of at least one disadvantage to that method:

If you are trying to create an AlertDialog with AlertDialog.Builder, the Application context won't work. I believe you need the context for the current Activity...

Ciprian answered 12/8, 2011 at 1:7 Comment(2)
That's right. If you use the application context for that, you may see your dialog hidden under foreground activities.Tabor
+1 first of all. And the possible error that comes is Unable to start activity ComponentInfo{com.samples/com.MyActivity}: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an applicationSugared
G
16

Kotlin

open class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        mInstance = this
    }

    companion object {
        lateinit var mInstance: MyApp
        fun getContext(): Context? {
            return mInstance.applicationContext
        }
    }
}

and get Context like

MyApp.mInstance

or

MyApp.getContext()
Goldarn answered 21/9, 2018 at 12:59 Comment(0)
S
12

If you're open to using RoboGuice, you can have the context injected into any class you want. Here's a small sample of how to do it with RoboGuice 2.0 (beta 4 at time of this writing)

import android.content.Context;
import android.os.Build;
import roboguice.inject.ContextSingleton;

import javax.inject.Inject;

@ContextSingleton
public class DataManager {
    @Inject
    public DataManager(Context context) {
            Properties properties = new Properties();
            properties.load(context.getResources().getAssets().open("data.properties"));
        } catch (IOException e) {
        }
    }
}
Snivel answered 29/2, 2012 at 14:46 Comment(0)
A
9

I've used this at some point:

ActivityThread at = ActivityThread.systemMain();
Context context = at.getSystemContext();

This is a valid context I used at getting system services and worked.

But, I used it only in framework/base modifications and did not try it in Android applications.

A warning that you must know: When registering for broadcast receivers with this context, it will not work and you will get:

java.lang.SecurityException: Given caller package android is not running in process ProcessRecord

Alyssa answered 8/5, 2014 at 10:22 Comment(0)
D
8

If you don't want to modify the manifest file, you can manually store the context in a static variable in your initial activity:

public class App {
    private static Context context;

    public static void setContext(Context cntxt) {
        context = cntxt;
    }

    public static Context getContext() {
        return context;
    }
}

And just set the context when your activity (or activities) start:

// MainActivity

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // Set Context
    App.setContext(getApplicationContext());

    // Other stuff
}

Note: Like all other answers, this is a potential memory leak.

Donelu answered 14/3, 2018 at 21:2 Comment(3)
What exactly will it be leaking since the context in this case is bound to the application? If the application dies, so does everything else.Lawman
Is there anyway of preventing this leak on static context references?Landau
No, since you are setting the context with getApplicationContext() it is not going to leak activity contexts. However, it may return null in a non-UI thread running beyond the activity.Dorie
A
8

in Kotlin, putting Context/App Context in companion object still produce warning Do not place Android context classes in static fields; this is a memory leak (and also breaks Instant Run)

or if you use something like this:

    companion object {
        lateinit var instance: MyApp
    }

It's simply fooling the lint to not discover the memory leak, the App instance still can produce memory leak, since Application class and its descendant is a Context.

Alternatively, you can use functional interface or Functional properties to help you get your app context.

Simply create an object class:

object CoreHelper {
    lateinit var contextGetter: () -> Context
}

or you could use it more safely using nullable type:

object CoreHelper {
    var contextGetter: (() -> Context)? = null
}

and in your App class add this line:


class MyApp: Application() {

    override fun onCreate() {
        super.onCreate()
        CoreHelper.contextGetter = {
            this
        }
    }
}

and in your manifest declare the app name to . MyApp


    <application
            android:name=".MyApp"

When you wanna get the context simply call:

CoreHelper.contextGetter()

// or if you use the nullable version
CoreHelper.contextGetter?.invoke()

Hope it will help.

Aronarondel answered 3/8, 2019 at 18:1 Comment(1)
This corehelper's object class will be initialised and can be used through out activities at later stage? Sorry I am new to kotlinPoler
K
6

According to this source you can obtain your own Context by extending ContextWrapper

public class SomeClass extends ContextWrapper {

    public SomeClass(Context base) {
      super(base);
    }

    public void someMethod() {
        // notice how I can use "this" for Context
        // this works because this class has it's own Context just like an Activity or Service
        startActivity(this, SomeRealActivity.class);

        //would require context too
        File cacheDir = getCacheDir();
    }
}

JavaDoc for ContextWrapper

Proxying implementation of Context that simply delegates all of its calls to another Context. Can be subclassed to modify behavior without changing the original Context.

Kubetz answered 13/12, 2016 at 8:29 Comment(1)
This is interesting. Good to learn about ContextWrapper. However, if you need to pass in the application context to this constructor, you still need to get it from somewhere.Fao
L
5

You can use the following:

MainActivity.this.getApplicationContext();

MainActivity.java:

...
public class MainActivity ... {
    static MainActivity ma;
...
    public void onCreate(Bundle b) {
         super...
         ma=this;
         ...

Any other class:

public ...
    public ANY_METHOD... {
         Context c = MainActivity.ma.getApplicationContext();
Leanneleanor answered 6/4, 2013 at 17:25 Comment(3)
This only works if you are inside an inner class, which is hardly the case in the OP.Colossae
This would work as long as the ANY_METHOD is called after MainActivity is created, but keeping static references to activities almost inevitably introduces memory leaks (as other responses to OP's question already mention), so if you really must keep a static reference, use the application context only.Caudate
Inner classes are evil. Worst part is that a lot of people do that for AsyncTasks and things like that, because many tutorials do it that way...Duffey
R
5

If you for some reason want Application context in any class, not just those extending application/activity, maybe for some factory or helper classes. You can add the following singleton to your app.

public class GlobalAppContextSingleton {
    private static GlobalAppContextSingleton mInstance;
    private Context context;

    public static GlobalAppContextSingleton getInstance() {
        if (mInstance == null) mInstance = getSync();
        return mInstance;
    }

    private static synchronized GlobalAppContextSingleton getSync() {
        if (mInstance == null) mInstance = 
                new GlobalAppContextSingleton();
        return mInstance;
    }

    public void initialize(Context context) {
        this.context = context;
    }

    public Context getApplicationContext() {
        return context;
    }
}

then initialize it in your application class's onCreate with

GlobalAppContextSingleton.getInstance().initialize(this);

use it anywhere by calling

GlobalAppContextSingleton.getInstance().getApplicationContext()

I don't recommend this approach to anything but application context however. As it can cause memory leaks.

Ruano answered 23/2, 2016 at 14:20 Comment(1)
It's not like the class/method names are set in stone, kept it long and (hopefully) descriptive for a Q&A, shortened it for my own use.Ruano
A
4

I think you need a body for the getAppContext() method:

public static Context getAppContext()
   return MyApplication.context; 
Aerolite answered 18/8, 2011 at 14:15 Comment(0)
R
2

I just released a jQuery-inspired framework for Android called Vapor API that aims to make app development simpler.

The central $ facade class maintains a WeakReference (link to awesome Java blog post about this by Ethan Nicholas) to the current Activity context which you can retrieve by calling:

$.act()

A WeakReference maintains a reference without preventing the garbage collection reclaiming the original object, so you shouldn't have a problem with memory leaks.

The downside of course is that you run the risk that $.act() could return null. I have not come across this scenario yet though, so it's perhaps just a minimal risk, worth mentioning.

You can also set the context manually if you are not using VaporActivity as your Activity class:

$.act(Activity);

Also, much of the Vapor API framework uses this stored context inherently which might mean you needn't store it yourself at all if you decide to use the framework. Check out the site for more information and samples.

I hope that helps :)

Ref answered 26/2, 2013 at 10:50 Comment(8)
Apparently this just got downvoted.. an explanation would be nice!?Ref
I didn't downvote this, but Javascript has nothing to do with the question at hand, that would explain any downvotes you may have had! Cheers.Tussock
That would be pretty nonsensical given it's inspired by some aspects of jQuery like a fluent interface, and its abstractions.. those are principles agnostic of the underlying language!Ref
I get your idea and your explanation, it has context, but, go figure what other users think. In any case, I am with you!Tussock
So you're downvoting it because it was inspired by the API semantics of a framework that isn't on the same platform?! I think you guys miss the point of applying platform-agnostic principles.....................................Ref
this answer is totally unrelated to JavaScript. Read the answer before you downvote :/Kubetz
In fact, this answer inspired me to use the convenient JQuery class naming. But it has nothing to do with JQuery. People should read better! Idea of using a WeakReference is beautiful!Dorie
@EugeneKartoyev WeakReference is anything but recommended.Rios
F
2

I use a variation of the Singleton design pattern to help me with this.

import android.app.Activity;
import android.content.Context;

public class ApplicationContextSingleton {
    private static Activity gContext;

    public static void setContext( Activity activity) {
        gContext = activity;
    }

    public static Activity getActivity() {
        return gContext;
    }

    public static Context getContext() {
        return gContext;
    }
}

I then call ApplicationContextSingleton.setContext( this ); in my activity.onCreate() and ApplicationContextSingleton.setContext( null ); in onDestroy();

Forwards answered 30/12, 2014 at 19:20 Comment(2)
If all you need is context you can call activity.getApplicationContext(); That can be held onto statically without having to worry about leaks.Winstonwinstonn
this will produce memory leaksKubetz
R
2

Rohit's answer seems correct. However, be aware that AndroidStudio's "Instant Run" depends on not having static Context attributes in your code, as far as I know.

Rehnberg answered 12/7, 2018 at 13:4 Comment(1)
You are right. And it will also result to memory leaks!Corabella
A
1

Today the right way to have context is to use dependency injection. For instance, one can use Hilt to inject context at any place it is needed. Let's say one needs context in some database manager, then this can be resolved in the following way:

Add Hilt in Gradle:

implementation "com.google.dagger:hilt-android:2.35"
kapt "com.google.dagger:hilt-android-compiler:2.35"

Define Application class with @HiltAndroidApp annotation (let it inject the database manager for example):

@HiltAndroidApp
class MyApplication : Application() {

    @Inject
    lateinit var dbManager: DBManager

    override fun onCreate() {
        super.onCreate()
        dbManager.initDB()
    }
}

Define Database manager (let it be @Singleton for example as well):

@Singleton
class DBManager @Inject constructor(
    @ApplicationContext private val context: Context
) {

    fun initDB() {
        // context is avaiable
        databaseInit(context)
    }
}

And that's it. The DBManager can access context in the right way without memory leaks.

Ajar answered 26/5, 2021 at 1:42 Comment(0)
E
1

Another alternative to get context without subclassing the Application object and without using hidden classes would be to use a ContentProvider. Once the onCreate method is called, the context should be available. You can do something like this in Kotlin

class ContextContentProvider : ContentProvider() {
    override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?) = 0

    override fun getType(uri: Uri): String? = null

    override fun insert(uri: Uri, values: ContentValues?): Uri? = null

    override fun onCreate(): Boolean {
        applicationContext = context
        return true
    }

    override fun query(
        uri: Uri, projection: Array<String>?, selection: String?,
        selectionArgs: Array<String>?, sortOrder: String?
    ): Cursor? = null

    override fun update(
        uri: Uri, values: ContentValues?, selection: String?,
        selectionArgs: Array<String>?
    ) = 0

    companion object {
        private var applicationContext: Context? = null

        @JvmStatic
        fun applicationContext() = applicationContext
    }
}

Anywhere you need the context, you can call ContextContentProvider.applicationContext() method

Make sure to use a different authority in the AndroidManifest.xml if you already have another content provider and the content provider is not exported.

<application>
    <provider
        android:name=".ContextContentProvider"
        android:authorities="${applicationId}.ContextContentProvider"
        android:enabled="true"
        android:exported="false" />
</application>
Emblazon answered 28/2, 2022 at 21:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.