getApplication()与getApplicationContext()


417

我找不到满意的答案,所以我们开始:Activity/Service.getApplication()和有Context.getApplicationContext()什么关系?

在我们的应用程序中,两个都返回相同的对象。在ActivityTestCase然而,嘲讽的应用程序将getApplication()回来与模拟,但getApplicationContext仍然会返回一个不同的上下文实例(一个由Android注入)。那是个错误吗?是故意的吗?

首先,我什至不了解其中的区别。在测试套件之外是否有案例,两个调用可能返回不同的对象?什么时候,为什么?而且,为什么getApplicationActivityService上定义了,但没有定义Context?难道不应该在任何地方都可以使用有效的应用程序实例吗?


8
好问题。测试的东西有点神秘(众所周知)。但是我想知道,如果您没有Application在应用程序中显式创建对象,那么这两个方法调用之间是否存在任何区别?
Christopher Orr

Answers:


366

非常有趣的问题。我认为这主要是语义上的意思,也可能是由于历史原因。

尽管在当前的Android Activity和Service实现中,getApplication()并且getApplicationContext()返回相同的对象,但不能保证总是如此(例如,在特定的供应商实现中)。

因此,如果要在清单中注册的Application类,则永远不要调用getApplicationContext()并将其强制转换为应用程序,因为它可能不是应用程序实例(显然是测试框架所经历的)。

为什么getApplicationContext()首先存在?

getApplication()仅在Activity类和Service类中可用,而getApplicationContext()在Context类中声明。

这实际上意味着一件事:当在广播接收器中编写代码时,该代码不是上下文,而是在其onReceive方法中提供了上下文,则只能调用getApplicationContext()。这也意味着您不能保证可以在BroadcastReceiver中访问您的应用程序。

查看Android代码时,您会看到,将其附加后,活动将接收基本上下文和应用程序,并且这些参数是不同的。getApplicationContext()将其委托给baseContext.getApplicationContext()

还有一件事:文档说,在大多数情况下,您无需将Application子类化:

通常无需继承Application。在大多数情况下,静态单例可以以更模块化的方式提供相同的功能。如果您的单身人士需要全局上下文(例如,注册广播接收者),则可以为检索单身人士的功能提供一个 在首次构造单身人士时在Context内部使用Context.getApplicationContext()的功能。

我知道这不是一个精确的答案,但是仍然可以回答您的问题吗?


89
@Piwaï:不要听文档。子类化android.app.Application是完整的超级帮助。例如,我在初始化数据库时遇到了无尽的问题。一旦移入Application.onCreate它,就像一个魅力。现在Application,我将在系统范围内进行所有初始化,并且如果没有它,我将不会编写其他应用程序。
马丁

9
@Martin不听文档通常意味着您的代码将来可能会中断,甚至在意外情况下现在也会中断,失去可移植性,表现不佳,阻止平台开发人员进行有益的更改(这打破了您错误地做出的假设,尽管它是仅基于当前的实现,而不基于文档)。我认为这是非常糟糕的行为,也是非常糟糕的建议。
Palec 2014年

17
@Palec:“通常不需要子类化应用程序。” —这只是提示。我仍然按预期方式使用正式记录的功能。-我曾经一开始使用那些“静态单例”,但事实证明它们是一个痛苦。-懒惰初始化存在其问题。特别是与仪器测试一起使用时。—我仍然有那些Singleton,用于模块化,但是我在android.app.Application子类的onCreate中实例化了它们。- 奇迹般有效。
马丁

9
@马丁我应该明确指出:我的反应只涉及第一句话。“不要听文档。” 这通常是非常危险的建议。但是“这只是一个提示-如果您有理由,在这种情况下可以忽略文档,我将向您展示…”对我来说绝对可以。
Palec 2014年

3
“在广播接收器中编写代码时,该代码不是上下文,而是在其onReceive方法中提供了上下文,您只能调用getApplicationContext()。这也意味着您不能保证可以在BroadcastReceiver中访问您的应用程序。 ” 。那么我们该怎么做才能访问BroadcastReceiver中的应用程序类?
Dr.jacky

30

比较getApplication()getApplicationContext()

getApplication返回一个Application对象,该对象将允许您管理全局应用程序状态并响应某些设备情况(例如onLowMemory()和)onConfigurationChanged()

getApplicationContext返回全局应用程序上下文-与其他上下文的不同之处在于,例如,活动结束时,Android可能会破坏(或使活动上下文不可用)活动上下文。在您的Application对象存在时(与特定对象无关),Application上下文始终保持可用状态,Activity因此您可以将其用于诸如Notifications之类的事情,这些事情需要一个可以长期使用且独立于瞬态UI对象的上下文。

我想这取决于您的代码在做什么,无论这些是否相同-尽管在正常使用中,我希望它们会有所不同。


19
但是an Application 一个Context(它继承自它),并且在运行时,两个方法都返回相同的实例。那有什么区别呢?
Matthias

3
区别在于范围。您的应用程序上下文的有效期比活动上下文更长,因为该活动可能仅在很短的时间内被使用,而您的应用程序可能包含许多活动。您的活动上下文至少在第一个活动开始时开始到最后一个活动结束时之间有效。它们都是上下文,但是一个持久并且不会改变,但是其他的则是短暂的,并且不同的实例可能具有不同的上下文。
RivieraKid 2011年

16
我认为您可能误解了我的问题。我并不是要询问Activity上下文和Application上下文之间的区别。我正在考虑Application(这是全局的,唯一的应用程序上下文)与getApplicationContext返回值之间的区别。后者实际上在Android 1.6之前无法运行;它曾经总是返回null
Matthias

1
@Matthias在我看来仍然很重要。上下文由Android系统本身注入(实现),而Application继承并扩展了Context。可以很容易地嘲笑应用程序类(如您所说),然后证明应用程序类(在测试项目中)确实做了一些“魔术”来实现它(可能忽略了注入的Context),这不是一个安全的押注吗?
奥德里斯

3
再来?抱歉,我仍然看不到如何回答我的问题。
Matthias

30

它似乎与上下文包装有关。从派生的大多数类Context实际上是一个ContextWrapper,本质上是委托给另一个上下文,可能由包装程序进行更改。

上下文是支持模拟和代理的通用抽象。由于许多上下文都绑定到寿命有限的对象(例如)Activity,因此需要一种方法来获取寿命更长的上下文,以实现诸如注册将来的通知之类的目的。这是通过实现的Context.getApplicationContext()。逻辑实现是返回全局Application对象,但是没有什么可以阻止上下文实现返回具有合适生存期的包装器或代理。

活动和服务更具体地与Application对象相关联。我认为,这样做的用处是,您可以在清单中创建并注册一个自定义类,该自定义类派生自该类Application并确定Activity.getApplication()Service.getApplication()将返回该特定类型的特定对象,您可以将该类型转换为派生Application类并用于任何用途自定义的目的。

换句话说,getApplication()保证返回一个Application对象,而getApplicationContext()可以自由返回一个代理。


当您说“上下文是支持模拟和代理的通用抽象”时,您确切地“代理”是什么意思?您能给我一些参考吗?我发现整个上下文问题都令人费解。
蒂亚戈

@Tiago这个答案可以帮助您更好地理解:stackoverflow.com/questions/10641144/…–
superuser

-13

为了回答这个问题,getApplication()返回一个Application对象,而getApplicationContext()返回一个Context对象。根据您自己的观察,我将假定两者的Context都是相同的(即在幕后Application类调用后者的函数来填充基类的Context部分或发生某些等效操作)。如果只需要上下文,则调用哪个函数并不重要。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.