何时调用活动上下文或应用程序上下文?

When to call activity context OR application context?

提问人:Norfeldt 提问时间:9/4/2011 最后编辑:Brian Tompsett - 汤莱恩Norfeldt 更新时间:5/28/2019 访问量:83963

问:

关于这两个上下文是什么,已经有很多帖子了。但我仍然没有完全正确

据我了解,到目前为止: 每个都是其类的一个实例,这意味着一些程序员建议您尽可能多地使用,以免“泄漏”任何内存。这是因为另一个(获取实例上下文)指向每次用户倾斜手机或离开应用程序等时都会被销毁的实例。显然,垃圾回收器(GC)没有捕获,因此使用了太多内存。this.getApplicationContext()thisActivityActivity

但是,任何人都可以想出一些非常好的编码示例,在这些示例中,使用它们是正确的(获取当前实例的上下文),而应用程序上下文将无用/错误?thisActivity

这个 android-context

评论


答:

4赞 SBerg413 9/4/2011 #1

当应使用活动上下文与应用程序上下文时,两个很好的例子是显示 Toast 消息或内置对话框消息时,因为使用应用程序上下文将导致异常:

ProgressDialog.show(this, ....);

Toast t = Toast.makeText(this,....);

这两者都需要来自活动上下文的信息,而这些信息未在应用程序上下文中提供。

评论

6赞 김준호 3/17/2015
嗯。您测试了哪个 Android 操作系统版本?我已经在 4.4.4 上进行了测试,效果很好。此外,正如 @Andi Jay 所提到的,官方 Android 开发者文档在其示例代码中使用了应用程序上下文。developer.android.com/guide/topics/ui/notifiers/......
1赞 Ojonugwa Jude Ochalifu 7/6/2015
@Chinese的名字,是的,它可能会起作用,但在该应用程序未来的某个时候,它也会崩溃。发生在我身上好几次。
1赞 Jemshit 8/5/2016
当我在 Toast 中使用 Activity 上下文时,它会泄漏内存!
424赞 CommonsWare 9/4/2011 #2

getApplicationContext()几乎总是错的。哈克伯恩女士(以及其他)非常明确地表示,只有在你知道为什么要使用时才使用,并且只有在需要使用时才使用。getApplicationContext()getApplicationContext()getApplicationContext()

坦率地说,“一些程序员”使用(或在较小程度上)是因为他们的 Java 经验有限。它们实现了一个内部类(例如,一个 中的 for a),并且需要一个 .他们不是用来获取外部类,而是使用 or 来获取对象。getApplicationContext()getBaseContext()OnClickListenerButtonActivityContextMyActivity.thisthisgetApplicationContext()getBaseContext()Context

只有当你知道你需要的东西时,你才会使用,这些东西的寿命可能比你所拥有的任何其他东西都长。方案包括:getApplicationContext()ContextContext

  • 如果您需要与本身具有全局范围的绑定的东西,请使用。例如,我使用 in 来表示要用于服务的静态。由于这是静态的,并且我需要一个来创建它,因此使用起来是最安全的。getApplicationContext()ContextgetApplicationContext()WakefulIntentServiceWakeLockWakeLockContextPowerManagergetApplicationContext()

  • 当您从 绑定到 时,如果您希望通过 在实例之间传递(即绑定的句柄),请使用 。Android 在内部通过这些绑定跟踪绑定,并保存对创建绑定的引用。如果从 绑定,则新实例将具有对 的引用,该引用具有对旧实例的隐式引用,并且旧实例不能被垃圾回收。getApplicationContext()ServiceActivityServiceConnectionActivityonRetainNonConfigurationInstance()ServiceConnectionsContextsActivityActivityServiceConnectionActivityActivity

一些开发人员将自定义子类用于他们自己的全局数据,他们通过 检索这些数据。这当然是可能的。我更喜欢静态数据成员,如果没有其他原因,您只能有一个自定义对象。我使用自定义对象构建了一个应用程序,发现它很痛苦。哈克伯恩女士也同意这一立场ApplicationgetApplicationContext()ApplicationApplication

以下是随身携带的原因:getApplicationContext()

  • 它不是一个完整的,支持所做的一切。您将尝试用它执行的各种操作都将失败,主要与 GUI 有关ContextActivityContext

  • 它可能会造成内存泄漏,如果 from 保留了您调用它而您没有清理的内容。有了 ,如果它抓住了一些东西,一旦垃圾被收集起来,其他所有东西也会被冲走。该对象在进程的生存期内保留。ContextgetApplicationContext()ActivityActivityApplication

评论

27赞 CommonsWare 9/5/2011
@Norfeldt:仅供参考,您评论中的链接链接回此答案。
2赞 Norfeldt 9/6/2011
谢谢。。这是链接: stackoverflow.com/questions/5796611/...它描述了我害怕使用它而得到的内存泄漏
6赞 CommonsWare 3/25/2013
@djaqeel:你引述的后半部分几乎是正确的。最好表述为“不要为活动提供比活动生存时间更长的内容的上下文,例如静态数据成员”。但是,您仍然只有在确切地知道在特定情况下为什么需要它时才使用。夸大布局?使用活动。绑定到服务,您需要该绑定才能在配置更改后继续存在?使用 ,以便绑定不绑定到实例。getApplicationContext()getApplicationContext()Activity
2赞 Sever 10/24/2013
@CommonsWare:为什么 getApplicationContext() 几乎总是错误的?我怎么能看到 android-developers.blogspot.de/2009/01/...,为了避免与上下文相关的内存泄漏,我们应该使用上下文应用程序而不是上下文活动
7赞 CommonsWare 10/24/2013
@Sever:我在回答中谈到了这一点。Dave Smith 还发表了一篇出色的博客文章,介绍了上下文: doubleencore.com/2013/06/context 他的总结段落:“在大多数情况下,使用您正在使用的封闭组件中直接可用的上下文。您可以安全地保留对它的引用,只要该引用不超过该组件的生命周期。一旦您需要从超出 Activity 或 Service 的对象(即使是暂时的)保存对 Context 的引用,请将您保存的引用切换到应用程序上下文。
51赞 Andi Jay 6/15/2012 #3

我认为 SDK 网站上有很多东西记录得很差,这是其中之一。我要说的是,似乎最好默认使用应用程序上下文,并且只在真正需要时才使用活动上下文。我见过唯一需要活动上下文的地方是进度对话框。SBERG412声称您必须对 Toast 消息使用活动上下文,但 Android 文档清楚地显示了正在使用的应用程序上下文。由于这个 Google 示例,我一直将应用程序上下文用于 Toast。如果这样做是错误的,那么谷歌就把球丢在这里了。

以下是需要考虑和审查的更多内容:

对于 Toast 消息,Google Dev Guide 使用应用程序上下文,并明确说明要使用它:Toast 通知

在开发指南的对话框部分中,可以看到 AlertDialog.Builder 使用应用程序上下文,然后进度栏使用活动上下文。谷歌没有对此进行解释。对话 框

使用应用程序上下文的一个很好的理由是,当您想要处理配置更改(如方向更改)时,并且希望保留需要上下文(如视图)的对象。如果您查看此处:运行时更改 有关使用活动上下文时需要注意,这可能会造成泄漏。这可以通过具有要保留的视图的应用程序上下文来避免(至少这是我的理解)。在我正在编写的应用程序中,我打算使用应用程序上下文,因为我试图在方向更改时保留一些视图和其他内容,并且我仍然希望在方向更改时销毁和重新创建活动。因此,我必须使用应用程序上下文来避免内存泄漏(请参阅避免内存泄漏)。在我看来,使用应用程序上下文而不是活动上下文似乎有很多充分的理由,在我看来,您似乎会比活动上下文更频繁地使用它。这就是我读过的许多 Android 书籍似乎都是这样做的,这也是我见过的许多 Google 示例所做的。

Google 文档确实让人觉得在大多数情况下使用应用程序上下文是完全可以的,事实上,在他们的示例中(至少我见过的示例)中比使用活动上下文更频繁地出现。如果使用应用程序上下文真的是一个问题,那么谷歌真的需要更加重视这一点。他们需要说清楚,他们需要重做一些例子。我不会把这完全归咎于没有经验的开发人员,因为权威机构(Google)确实让它看起来使用应用程序上下文不是问题。

评论

5赞 SAS 5/29/2014
我完全同意。CommonsWare的回答让我有点惊讶。我很高兴我找到了这个问题,因为在 Google 文档中表明使用 getApplicationContext 可能非常危险。
3赞 Ganesh Katikar 1/6/2014 #4

应用程序上下文一直存在,直到您的应用程序处于活动状态,它不依赖于活动生命周期,但上下文使对象保持长期存在。如果临时使用的对象,则使用应用程序上下文和活动上下文时,使用完全相反的应用程序上下文

12赞 Zohra Khan 4/11/2014 #5

使用哪个上下文?

有两种类型的上下文:

  1. 应用程序上下文与应用程序相关联,并且在应用程序的整个生命周期中始终相同 - 它不会更改。因此,如果您使用的是 Toast,则可以使用应用程序上下文甚至活动上下文(两者),因为 Toast 可以从应用程序中的任何位置显示,并且不会附加到特定窗口。但是有很多例外,一个例外是当你需要使用或传递活动上下文时。

  2. 活动上下文与活动相关联,如果活动被销毁,则可以销毁 -- 单个应用程序可能有多个活动(很可能)。有时,您绝对需要活动上下文句柄。例如,如果启动一个新活动,则需要在其 Intent 中使用活动上下文,以便根据活动堆栈将新启动活动连接到当前活动。但是,您也可以使用应用程序的上下文来启动新活动,但随后需要在意图中设置标志以将其视为新任务。Intent.FLAG_ACTIVITY_NEW_TASK

让我们考虑一些情况:

  • MainActivity.this引用扩展 Activity 类的 MainActivity 上下文,但基类 (activity) 也扩展了 Context 类,因此可用于提供活动上下文。

  • getBaseContext()提供活动上下文。

  • getApplication()提供应用程序上下文。

  • getApplicationContext()还提供应用程序上下文。

欲了解更多信息,请查看此链接

评论

0赞 CybeX 1/24/2018
如果需要在应用程序中显示 AlertDialog,例如显示结果的异步进程,该怎么办?这方面的一个例子可能是:用户点击下载,这会触发 的下载请求,当收到完成的信号时,它应该显示一个对话框,例如“你想用这个下载做什么?我的(hack)解决方案将最新的保存在类中,并在下载完成后请求当前。但是,我怀疑这是否是正确的实现。TL;DR 如何在应用程序中的任何位置显示 AlertDialog?downloadmanagerActivitystaticApplicationActivity
0赞 ExiRouS 6/18/2018
@KGCybeX 如果要在下载完成后在应用中的任何位置显示任何内容,则应在 Activity 上手动注册一个广播接收器,以侦听下载服务将广播的特定消息,并在收到消息后执行任何操作,或者直接将 Activity 附加到该服务。
47赞 CommonSenseCode 2/4/2016 #6

我使用此表作为何时使用不同类型的上下文的指南,例如应用程序上下文(即:)和活动上下文,以及BroadcastReceiver上下文getApplicationContext()

enter image description here

所有优点都归原作者所有,以获取更多信息。

7赞 Malachiasz 3/16/2016 #7

我想知道为什么不对它支持的每个操作使用应用程序上下文。最后,它降低了内存泄漏和缺少 getContext() 或 getActivity() 的 null 检查的可能性(当使用注入的应用程序上下文或通过 Application 的静态方法获取时)。像 Hackborn 女士那样的陈述,即仅在需要时才使用应用程序上下文,如果没有解释原因,对我来说似乎没有说服力。但似乎我找到了一个不发誓的原因:

发现某些不遵循这些规则的 Android 版本/设备组合存在问题。例如,如果我有一个传递了 Context 的 BroadcastReceiver,我将该 Context 转换为 Application Context,然后尝试在 Application Context 上调用 registerReceiver(),那么在许多情况下,这都可以正常工作,但也有很多情况下我因为 ReceiverCallNotAllowedException 而崩溃。这些崩溃发生在从 API 15 到 API 22 的各种 Android 版本上。https://possiblemobile.com/2013/06/context/#comment-2443283153

因为不能保证下表中描述的 Application Context 支持的所有操作都适用于所有 Android 设备! enter image description here