getApplication() vs. getApplicationContext()
Asked Answered
M

4

449

I couldn't find a satisfying answer to this, so here we go: what's the deal with Activity/Service.getApplication() and Context.getApplicationContext()?

In our application, both return the same object. In an ActivityTestCase however, mocking the application will make getApplication() come back with the mock, but getApplicationContext will still return a different context instance (one injected by Android). Is that a bug? Is it on purpose?

I don't even understand the difference in the first place. Are there cases outside a test suite where both calls may come back with different objects? When and why? Moreover, why is getApplication defined on Activity and Service, but not on Context? Shouldn't there always be a valid application instance available from anywhere?

Monad answered 16/2, 2011 at 15:45 Comment(1)
Nice question. The testing stuff is a bit of a mystery (as you well know). But I wonder if any difference manifests itself in these two method calls if you don't explicitly create an Application object in your app.Liston
S
392

Very interesting question. I think it's mainly a semantic meaning, and may also be due to historical reasons.

Although in current Android Activity and Service implementations, getApplication() and getApplicationContext() return the same object, there is no guarantee that this will always be the case (for example, in a specific vendor implementation).

So if you want the Application class you registered in the Manifest, you should never call getApplicationContext() and cast it to your application, because it may not be the application instance (which you obviously experienced with the test framework).

Why does getApplicationContext() exist in the first place ?

getApplication() is only available in the Activity class and the Service class, whereas getApplicationContext() is declared in the Context class.

That actually means one thing : when writing code in a broadcast receiver, which is not a context but is given a context in its onReceive method, you can only call getApplicationContext(). Which also means that you are not guaranteed to have access to your application in a BroadcastReceiver.

When looking at the Android code, you see that when attached, an activity receives a base context and an application, and those are different parameters. getApplicationContext() delegates it's call to baseContext.getApplicationContext().

One more thing : the documentation says that it most cases, you shouldn't need to subclass Application:

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.

I know this is not an exact and precise answer, but still, does that answer your question?

Spinose answered 20/7, 2011 at 9:52 Comment(9)
@Piwaï: Don't listen to the doc. Subclassing android.app.Application is super help full. For example I had endless problems initializing the database. Once moved into Application.onCreate it worked like a charm. Now I do all system wide initialisation in Application and I would not write another App without.Issuance
@Issuance Not listening to the docs generally means that your code may break in the future, or even now under unexpected conditions, lose portability, perform badly, prevent platform developers from making a beneficial change (that breaks the assumption you incorrectly made although it was based only on current implementation, not the docs). I think that this is pretty bad behavior and pretty bad piece of advice.Almena
@Palec: “There is normally no need to subclass Application.” — That is just hint. I still use officially documented functionality in the intended way. — I used to use those “static singletons” in the beginning and they turned out to be a pain in the a… — lazy initialisation has its problems. Especially when used with instrumentation tests. — I still have those Singletons for modularity but I instantiate them en block in the onCreate of an android.app.Application subclass. — works like a charm.Issuance
@Issuance I should have made it clear: My reaction concerned the first sentence only. “Don’t listen to the doc.” This is generally very dangerous piece of advice. But “This is just a hint – you can ignore the doc in this case if you have a reason and I’ll show you one…” sounds absolutely OK to me.Almena
btw Jake Wharton does this in get() method github.com/JakeWharton/u2020/blob/master/src/main/java/com/…Calamity
"when writing code in a broadcast receiver, which is not a context but is given a context in its onReceive method, you can only call getApplicationContext(). Which also means that you are NOT guaranteed to have access to your application in a BroadcastReceiver." .So what can we do to access to my application class in BroadcastReceiver?Palmy
"In most situation, static singletons can provide the same functionality in a more modular way" - How would one go on setting up singletons for the application object without extending the application class itself and assigning it to the variable that will be returned by the singleton?Togoland
I think it is important to add to @Almena & Martin 's discussion that the application is the only place one should define singletons in an android app, as the traditional static singleton pattern relies on consistent process IDs, which android OS will not guarantee you. If you are finding that your app is ANR'ing after coming back from long sleeps, that's probably why; if so, you may want to consolidate your dependency on that design pattern and perhaps investigate a DI library like Dagger that can organize and reliably produce your singletons (and non-singletons!) in the application.Midiron
@anthropicandroid I don't think you are entirely correct by saying "application is the only place one should define singletons" because it all depends on where you want to use it. If it is from a service, broadcast receiver, something Android system initiates, then probably yes, but if it is only "In-App" or UI related usage then it is fine to create singletons all over the place.Burtie
W
33

It seems to have to do with context wrapping. Most classes derived from Context are actually a ContextWrapper, which essentially delegates to another context, possibly with changes by the wrapper.

The context is a general abstraction that supports mocking and proxying. Since many contexts are bound to a limited-lifetime object such as an Activity, there needs to be a way to get a longer-lived context, for purposes such as registering for future notifications. That is achieved by Context.getApplicationContext(). A logical implementation is to return the global Application object, but nothing prevents a context implementation from returning a wrapper or proxy with a suitable lifetime instead.

Activities and services are more specifically associated with an Application object. The usefulness of this, I believe, is that you can create and register in the manifest a custom class derived from Application and be certain that Activity.getApplication() or Service.getApplication() will return that specific object of that specific type, which you can cast to your derived Application class and use for whatever custom purpose.

In other words, getApplication() is guaranteed to return an Application object, while getApplicationContext() is free to return a proxy instead.

Worrisome answered 1/11, 2012 at 0:26 Comment(2)
When you say "the context is a general abstraction that supports mocking and proxying" what do you mean by "proxying" exactly? Could you point me to some references? I find the whole Context thing quite convoluted.Togoland
@Tiago This answer can help you understand better: #10641644Gaddi
N
30

Compare getApplication() and getApplicationContext().

getApplication returns an Application object which will allow you to manage your global application state and respond to some device situations such as onLowMemory() and onConfigurationChanged().

getApplicationContext returns the global application context - the difference from other contexts is that for example, an activity context may be destroyed (or otherwise made unavailable) by Android when your activity ends. The Application context remains available all the while your Application object exists (which is not tied to a specific Activity) so you can use this for things like Notifications that require a context that will be available for longer periods and independent of transient UI objects.

I guess it depends on what your code is doing whether these may or may not be the same - though in normal use, I'd expect them to be different.

Nudism answered 16/2, 2011 at 16:47 Comment(6)
but an Application is a Context (it inherits from it), and at runtime, both methods return the same instance. So what's the difference?Monad
The difference is the scope. Your Application context will be valid far longer than, say, an Activity context because the activity may only be in use for a very short time, while your Application may consist of many Activities. Your Activity Context will be valid for at least as long as the duration that begins when the first activity is started and ends when the last activity. They are all Contexts, but one is longer lasting and doesn't change, but others are short-lived, and different instances may have different Contexts.Nudism
I think you may be misreading my question. I'm not asking for the difference between an Activity context and an Application context. I'm pondering the difference between Application (which is the global, unique application context) and whatever getApplicationContext returns. The latter was in fact non-functional before Android 1.6; it used to always return null.Monad
@Matthias In my opinion it is still relevant. Context is injected (implemented) by Android system itself, while Application inherits and extends Context. Application class can be easily mocked (as said by you) then isn't it a safe bet that it shows that Application class does some "magic" (in test project) to achieve it, possibly ignoring injected Context?Prohibition
Come again? I'm sorry, I still don't see how that answers my question.Monad
Context itself is provided by Android system, so when you use Context.doStuff() you get what's build in a core OS itself. On the other hand Application inherits Context so it can override bunch of stuff in it, right? I just speculate, that even in test project Context is still retrieved from OS, while Application class in test project is different from the one in non-test project, thus it can override some of Context members to allow mocking, etc., giving you different context. Mind you, this is just a speculation (-.Prohibition
S
-13

To answer the question, getApplication() returns an Application object and getApplicationContext() returns a Context object. Based on your own observations, I would assume that the Context of both are identical (i.e. behind the scenes the Application class calls the latter function to populate the Context portion of the base class or some equivalent action takes place). It shouldn't really matter which function you call if you just need a Context.

Sleigh answered 4/5, 2011 at 19:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.