关于android:何时调用活动上下文或应用程序上下文?

When to call activity context OR application context?

有很多关于这两种背景的帖子......但我仍然没有把它弄得恰到好处

据我所知,到目前为止:
每个都是它的类的一个实例,这意味着一些程序员建议你尽可能频繁地使用this.getApplicationContext(),以免"泄漏"任何内存。 这是因为其他this(获取Activity实例上下文)指向每次用户倾斜手机或离开应用程序等时正在销毁的Activity。显然垃圾收集器(GC)没有 抓住并因此使用太多记忆..

但任何人都可以想出一些非常好的编码示例,使用this(获取当前Activity实例的上下文)并且应用程序上下文将是无用/错误是正确的吗?


getApplicationContext()几乎总是错的。 Hackborn女士(以及其他人)非常明确地表示,当您知道使用getApplicationContext()的原因并且仅在需要使用getApplicationContext()时才使用getApplicationContext()

说实话,"一些程序员"使用getApplicationContext()(或getBaseContext(),在较小程度上)因为他们的Java经验有限。它们实现了一个内部类(例如,ActivityButtonOnClickListener)并且需要Context。他们使用getApplicationContext()getBaseContext()来获取Context对象,而不是使用MyActivity.this来获取外部类'this

只有当你知道自己需要一个Context的东西时,才能使用getApplicationContext(),而这些东西的寿命可能超过你拥有的任何其他Context。场景包括:

  • 如果您需要绑定到Context的东西,请使用getApplicationContext(),而Context本身将具有全局范围。我在WakefulIntentService中使用getApplicationContext(),用于服务所使用的静态WakeLock。因为WakeLock是静态的,并且我需要Context来获取PowerManager来创建它,所以使用getApplicationContext()是最安全的。

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

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

以下是无论何时何地不使用getApplicationContext()的原因:

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

  • 如果getApplicationContext()中的Context保留在您不能清理的调用所创建的内容上,则可能会造成内存泄漏。使用Activity,如果它保留了某些内容,一旦Activity被垃圾收集,其他所有内容都会被清除。 Application对象保留在进程的生命周期内。


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

这里有更多的思考和评论:

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

在Dev指南的对话框部分中,您会看到AlertDialog.Builder使用应用程序上下文,然后进度条使用活动上下文。谷歌没有解释这一点。
对话框

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

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


我使用此表作为何时使用不同类型的Context(如Application上下文(即:getApplicationContext())和活动上下文,以及BroadcastReceiver上下文的指导:

enter image description here

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


Which context to use?

上下文有两种类型:

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

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

  • 让我们考虑一些情况:

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

    • getBaseContext()提供活动背景。

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

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

    有关更多信息,请查看此链接。


    我想知道为什么不为它支持的每个操作使用Application Context。最后,它降低了内存泄漏的可能性,并且缺少对getContext()或getActivity()的空检查(当使用注入的应用程序上下文或通过Application中的静态方法获取时)。声明,就像Hackborn女士仅在需要时使用应用程序上下文一样,在没有解释原因的情况下对我来说似乎并不令人信服。但似乎我找到了一个不合理的原因:

    have found that there are issues on some Android version / device combinations that do not follow these rules. For instance, if I have a BroadcastReceiver that is passed a Context and I convert that Context to an Application Context and then try to call registerReceiver() on the Application Context there are many instances where this works fine, but also many instances where I get a crash because of a ReceiverCallNotAllowedException. These crashes occur on a wide range of Android versions from API 15 up to 22.
    https://possiblemobile.com/2013/06/context/#comment-2443283153

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


    应用程序上下文实时,直到您的应用程序仅存活,并且它不依赖于活动生命周期,但上下文保持对象长期存在。如果您临时使用的对象,那个时候使用Application Context和Activity Context完全对应Application Context。


    应该使用Activity上下文与Application上下文的两个很好的例子是在显示Toast消息或内置Dialog消息时,因为使用Application上下文会导致异常:

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

    要么

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

    这两者都需要来自Activity上下文的信息,而这些信息并未在Application上下文中提供。