提问人:Norfeldt 提问时间:9/4/2011 最后编辑:Brian Tompsett - 汤莱恩Norfeldt 更新时间:5/28/2019 访问量:83963
何时调用活动上下文或应用程序上下文?
When to call activity context OR application context?
问:
关于这两个上下文是什么,已经有很多帖子了。但我仍然没有完全正确
据我了解,到目前为止:
每个都是其类的一个实例,这意味着一些程序员建议您尽可能多地使用,以免“泄漏”任何内存。这是因为另一个(获取实例上下文)指向每次用户倾斜手机或离开应用程序等时都会被销毁的实例。显然,垃圾回收器(GC)没有捕获,因此使用了太多内存。this.getApplicationContext()
this
Activity
Activity
但是,任何人都可以想出一些非常好的编码示例,在这些示例中,使用它们是正确的(获取当前实例的上下文),而应用程序上下文将无用/错误?this
Activity
答:
当应使用活动上下文与应用程序上下文时,两个很好的例子是显示 Toast 消息或内置对话框消息时,因为使用应用程序上下文将导致异常:
ProgressDialog.show(this, ....);
或
Toast t = Toast.makeText(this,....);
这两者都需要来自活动上下文的信息,而这些信息未在应用程序上下文中提供。
评论
getApplicationContext()
几乎总是错的。哈克伯恩女士(以及其他)非常明确地表示,只有在你知道为什么要使用时才使用,并且只有在需要使用时才使用。getApplicationContext()
getApplicationContext()
getApplicationContext()
坦率地说,“一些程序员”使用(或在较小程度上)是因为他们的 Java 经验有限。它们实现了一个内部类(例如,一个 中的 for a),并且需要一个 .他们不是用来获取外部类,而是使用 or 来获取对象。getApplicationContext()
getBaseContext()
OnClickListener
Button
Activity
Context
MyActivity.this
this
getApplicationContext()
getBaseContext()
Context
只有当你知道你需要的东西时,你才会使用,这些东西的寿命可能比你所拥有的任何其他东西都长。方案包括:getApplicationContext()
Context
Context
如果您需要与本身具有全局范围的绑定的东西,请使用。例如,我使用 in 来表示要用于服务的静态。由于这是静态的,并且我需要一个来创建它,因此使用起来是最安全的。
getApplicationContext()
Context
getApplicationContext()
WakefulIntentService
WakeLock
WakeLock
Context
PowerManager
getApplicationContext()
当您从 绑定到 时,如果您希望通过 在实例之间传递(即绑定的句柄),请使用 。Android 在内部通过这些绑定跟踪绑定,并保存对创建绑定的引用。如果从 绑定,则新实例将具有对 的引用,该引用具有对旧实例的隐式引用,并且旧实例不能被垃圾回收。
getApplicationContext()
Service
Activity
ServiceConnection
Activity
onRetainNonConfigurationInstance()
ServiceConnections
Contexts
Activity
Activity
ServiceConnection
Activity
Activity
一些开发人员将自定义子类用于他们自己的全局数据,他们通过 检索这些数据。这当然是可能的。我更喜欢静态数据成员,如果没有其他原因,您只能有一个自定义对象。我使用自定义对象构建了一个应用程序,发现它很痛苦。哈克伯恩女士也同意这一立场。Application
getApplicationContext()
Application
Application
以下是不随身携带的原因:getApplicationContext()
它不是一个完整的,支持所做的一切。您将尝试用它执行的各种操作都将失败,主要与 GUI 有关。
Context
Activity
Context
它可能会造成内存泄漏,如果 from 保留了您调用它而您没有清理的内容。有了 ,如果它抓住了一些东西,一旦垃圾被收集起来,其他所有东西也会被冲走。该对象在进程的生存期内保留。
Context
getApplicationContext()
Activity
Activity
Application
评论
getApplicationContext()
getApplicationContext()
Activity
我认为 SDK 网站上有很多东西记录得很差,这是其中之一。我要说的是,似乎最好默认使用应用程序上下文,并且只在真正需要时才使用活动上下文。我见过唯一需要活动上下文的地方是进度对话框。SBERG412声称您必须对 Toast 消息使用活动上下文,但 Android 文档清楚地显示了正在使用的应用程序上下文。由于这个 Google 示例,我一直将应用程序上下文用于 Toast。如果这样做是错误的,那么谷歌就把球丢在这里了。
以下是需要考虑和审查的更多内容:
对于 Toast 消息,Google Dev Guide 使用应用程序上下文,并明确说明要使用它:Toast 通知
在开发指南的对话框部分中,可以看到 AlertDialog.Builder 使用应用程序上下文,然后进度栏使用活动上下文。谷歌没有对此进行解释。对话 框
使用应用程序上下文的一个很好的理由是,当您想要处理配置更改(如方向更改)时,并且希望保留需要上下文(如视图)的对象。如果您查看此处:运行时更改 有关使用活动上下文时需要注意,这可能会造成泄漏。这可以通过具有要保留的视图的应用程序上下文来避免(至少这是我的理解)。在我正在编写的应用程序中,我打算使用应用程序上下文,因为我试图在方向更改时保留一些视图和其他内容,并且我仍然希望在方向更改时销毁和重新创建活动。因此,我必须使用应用程序上下文来避免内存泄漏(请参阅避免内存泄漏)。在我看来,使用应用程序上下文而不是活动上下文似乎有很多充分的理由,在我看来,您似乎会比活动上下文更频繁地使用它。这就是我读过的许多 Android 书籍似乎都是这样做的,这也是我见过的许多 Google 示例所做的。
Google 文档确实让人觉得在大多数情况下使用应用程序上下文是完全可以的,事实上,在他们的示例中(至少我见过的示例)中比使用活动上下文更频繁地出现。如果使用应用程序上下文真的是一个问题,那么谷歌真的需要更加重视这一点。他们需要说清楚,他们需要重做一些例子。我不会把这完全归咎于没有经验的开发人员,因为权威机构(Google)确实让它看起来使用应用程序上下文不是问题。
评论
应用程序上下文一直存在,直到您的应用程序处于活动状态,它不依赖于活动生命周期,但上下文使对象保持长期存在。如果临时使用的对象,则使用应用程序上下文和活动上下文时,使用完全相反的应用程序上下文。
使用哪个上下文?
有两种类型的上下文:
应用程序上下文与应用程序相关联,并且在应用程序的整个生命周期中始终相同 - 它不会更改。因此,如果您使用的是 Toast,则可以使用应用程序上下文甚至活动上下文(两者),因为 Toast 可以从应用程序中的任何位置显示,并且不会附加到特定窗口。但是有很多例外,一个例外是当你需要使用或传递活动上下文时。
活动上下文与活动相关联,如果活动被销毁,则可以销毁 -- 单个应用程序可能有多个活动(很可能)。有时,您绝对需要活动上下文句柄。例如,如果启动一个新活动,则需要在其 Intent 中使用活动上下文,以便根据活动堆栈将新启动活动连接到当前活动。但是,您也可以使用应用程序的上下文来启动新活动,但随后需要在意图中设置标志以将其视为新任务。
Intent.FLAG_ACTIVITY_NEW_TASK
让我们考虑一些情况:
MainActivity.this
引用扩展 Activity 类的 MainActivity 上下文,但基类 (activity) 也扩展了 Context 类,因此可用于提供活动上下文。getBaseContext()
提供活动上下文。getApplication()
提供应用程序上下文。getApplicationContext()
还提供应用程序上下文。
欲了解更多信息,请查看此链接。
评论
downloadmanager
Activity
static
Application
Activity
我使用此表作为何时使用不同类型的上下文的指南,例如应用程序上下文(即:)和活动上下文,以及BroadcastReceiver上下文:getApplicationContext()
所有优点都归原作者所有,以获取更多信息。
我想知道为什么不对它支持的每个操作使用应用程序上下文。最后,它降低了内存泄漏和缺少 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
评论