getApplication()与getApplicationContext()

Mat*_*ias 407 android android-service android-context android-activity

我找不到令人满意的答案,所以我们在这里:有什么处理Activity/Service.getApplication()Context.getApplicationContext()

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

我甚至不了解首先的区别.测试套件外是否存在两个呼叫可能带有不同对象的情况?何时以及为何?此外,为什么getApplication定义上ActivityService,但不是Context?不应该随处可用的有效应用程序实例吗?

Pie*_*cau 361

非常有趣的问题.我认为它主要是语义,也可能是由于历史原因.

虽然在当前的Android Activity和Service实现中,getApplication()getApplicationContext()返回相同的对象,但无法保证始终如此(例如,在特定的供应商实现中).

所以,如果你想你的清单注册的应用程序类,你应该永远不会调用getApplicationContext(),并投射到您的应用程序,因为它可能不是应用程序实例(你显然与测试框架的经历).

为什么getApplicationContext()首先存在?

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

这实际上意味着一件事:当在广播接收器中编写代码时,它不是上下文但在其onReceive方法中给出了上下文,您只能调用getApplicationContext().这也意味着您无法保证能够在BroadcastReceiver中访问您的应用程序.

在查看Android代码时,您会看到在附加时,活动会收到基本上下文和应用程序,这些是不同的参数.getApplicationContext()委托它致电baseContext.getApplicationContext().

还有一件事:文档说大多数情况下,你不应该需要子类Application:

通常不需要子类Application.在大多数情况下,静态单例可以以更模块化的方式提供相同的功能.如果你的单例需要一个全局上下文(例如注册广播接收器),那么检索它的函数可以给出一个 在第一次构造单例时Context内部使用的Context.getApplicationContext()函数.

我知道这不是一个确切而准确的答案,但是,这仍然可以回答你的问题吗?

  • @Piwaï:不要听文件.子类化`android.app.Application`是超级帮助.例如,我在初始化数据库时遇到了无数问题.一旦进入`Application.onCreate`,它就像一个魅力.现在我在`Application`中进行所有系统范围的初始化,我不会在没有的情况下编写另一个App. (85认同)
  • @Palec:"通常没有必要继承Application." - 这只是提示.我仍然以预期的方式使用官方记录的功能. - 我曾经在开始使用那些"静态单身人士",结果证明这是一个痛苦... - 懒惰的初始化有它的问题.特别是与仪器测试一起使用时. - 我仍然有那些Singletons的模块化,但我在android.app.Application子类的onCreate中实例化它们.- 奇迹般有效. (15认同)
  • @Martin我应该说清楚:我的反应仅涉及第一句话."不要听医生说."这通常是非常危险的建议.但是"这只是一个提示 - 如果你有理由我可以忽略这个案例中的文档,我会告诉你一个......"对我来说听起来绝对可以. (9认同)
  • @Martin不听文档通常意味着您的代码将来可能会中断,甚至现在在意外情况下,丢失可移植性,执行不当,阻止平台开发人员进行有益的更改(这会打破您错误的假设,尽管它是仅基于当前实现,而不是文档).我认为这是非常糟糕的行为和非常糟糕的建议. (7认同)
  • "当在广播接收器中编写代码时,它不是上下文但在onReceive方法中给出了上下文,你只能调用getApplicationContext().这也意味着你不能保证在BroadcastReceiver中有权访问你的应用程序. " 那么我们可以做些什么来访问BroadcastReceiver中的应用程序类? (3认同)
  • 我认为重要的是要添加到@Palec & Martin 的讨论中,即应用程序是*唯一*应该在 android 应用程序中定义单例的地方,因为传统的静态单例模式依赖于一致的进程 ID,而 android 操作系统不会向你保证。如果您发现您的应用在长时间睡眠后出现 ANR 问题,这可能就是原因;如果是这样,您可能希望巩固您对该设计模式的依赖,并可能研究一个像 Dagger 这样的 DI 库,它可以在应用程序中组织和可靠地生成您的单例(和非单例!)。 (2认同)

Riv*_*Kid 30

比较getApplication()getApplicationContext().

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

getApplicationContext返回全局应用程序上下文 - 与其他上下文的区别在于,例如,当您的活动结束时,Android可能会销毁(或以其他方式使其不可用)活动上下文.应用程序上下文在您的Application对象存在时仍然可用(不依赖于特定的Activity),因此您可以将此用于需要上下文可用较长时间且独立于瞬态UI对象的通知之类的内容.

我想这取决于你的代码在做什么,无论这些可能是也可能不一样 - 尽管在正常使用中,我希望它们是不同的.

  • 但是`Application`*是一个`Context`(它继承自它),并且在运行时,两个方法都返回相同的实例.那有什么区别? (18认同)
  • 我想你可能会误解我的问题.我不是要求`Activity`上下文和`Application`上下文之间的区别.我在思考`Application`(这是全局的,唯一的应用程序上下文)和`getApplicationContext`返回之间的区别.后者在Android 1.6之前实际上是无功能的; 它曾经总是返回`null`. (16认同)
  • 不同之处在于范围.您的应用程序上下文的有效期远远超过活动上下文,因为活动可能只在很短的时间内使用,而您的应用程序可能包含许多活动.您的活动上下文的有效期至少与第一个活动开始时的持续时间一样长,最后一个活动结束时的持续时间.它们都是上下文,但是一个是持久的并且不会改变,但是其他的是短暂的,并且不同的实例可能具有不同的上下文. (3认同)
  • 再来?对不起,我仍然看不出这是如何回答我的问题的. (3认同)

use*_*4ce 29

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

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

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

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