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

Nor*_*ldt 259 android this android-context

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

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

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

Com*_*are 396

getApplicationContext()几乎总是错的.Hackborn女士(等等)已经非常明确,你getApplicationContext()当你知道为什么你使用getApplicationContext(),只有当你需要使用getApplicationContext().

坦率地说,"一些程序员"使用getApplicationContext()(或者getBaseContext(),在较小程度上),因为他们的Java经验是有限的.他们实现一个内部类(例如,OnClickListener用于ButtonActivity)和需要Context.他们使用或获取一个对象,而不是MyActivity.this用来获取外部类.thisgetApplicationContext()getBaseContext()Context

只有getApplicationContext()当您知道自己需要的Context东西可能比Context您可能使用的任何其他东西更长时,您才会使用.场景包括:

  • getApplicationContext()如果你需要一些与Context自身具有全局范围的东西,请使用.getApplicationContext()例如,我使用WakefulIntentService静态WakeLock来用于服务.由于这WakeLock是静态的,我需要Context得到在PowerManager创建它,它是最安全的使用getApplicationContext().

  • 使用getApplicationContext()时,您绑定到一个ServiceActivity,如果你希望将传递ServiceConnection(即句柄绑定)之间Activity通过实例onRetainNonConfigurationInstance().Android通过这些内部跟踪绑定,ServiceConnections并保存对Contexts创建绑定的引用.如果你绑定了Activity,那么新Activity实例将引用ServiceConnection一个对旧的隐式引用Activity,而旧的Activity不能被垃圾收集.

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

以下是不在getApplicationContext()任何地方使用的原因:

  • 它不是一个完整的Context,支持一切Activity.你将尝试用它做的各种事情Context都会失败,主要与GUI有关.

  • 它可能会造成内存泄漏,如果Contextfrom getApplicationContext()保留在您不能清理的调用所创建的内容上.随着Activity,如果持有到的东西,一旦Activity得到垃圾收集,一切冲走了.该Application对象在您的过程的生命周期中保留.

  • @Norfeldt:仅供参考,您评论中的链接会链接回此答案. (27认同)
  • @Sever:我在答案中说明了这一点.戴夫史密斯也有一篇很好的博客文章,涵盖了上下文:http://www.doubleencore.com/2013/06/context/他的摘要段落:"在大多数情况下,使用您可以从封闭组件直接获得的上下文只要该引用不超出该组件的生命周期,就可以安全地保存对它的引用.只要您需要从超出Activity或Service的对象中保存对Context的引用,甚至暂时将您保存的引用切换到应用程序上下文." (7认同)
  • @djaqeel:你引用的后半部分几乎是真的.它更好地表达为"不要将活动上下文赋予比活动更长寿的内容,例如静态数据成员".但是,当你知道为什么**在特定情况下你需要它时,你仍然只使用`getApplicationContext()`.夸大布局?使用活动.绑定到服务,您需要哪些绑定才能在配置更改后继续存在?使用`getApplicationContext()`,因此绑定不与`Activity`实例绑定. (6认同)
  • 谢谢你..这是链接:http://stackoverflow.com/questions/5796611/dialog-throwing-unable-to-add-window-token-null-is-not-for-an-application-wit它描述我害怕得到的内存泄漏 (2认同)
  • @CommonsWare:为什么 getApplicationContext() 几乎总是错误的?我如何在 http://android-developers.blogspot.de/2009/01/avoiding-memory-leaks.html 中看到,为了避免与上下文相关的内存泄漏,我们应该使用上下文应用程序而不是上下文活动 (2认同)

And*_*Jay 47

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

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

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

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

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

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

  • 我完全同意.CommonsWare的答案对我来说有点意外.我很高兴我发现了这个问题,因为谷歌的文档表明使用getApplicationContext会非常危险. (4认同)

Com*_*ode 36

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

在此输入图像描述

原创文章在这里获取更多信息.


Zoh*_*han 11

使用哪种上下文?

上下文有两种类型:

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

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

让我们考虑一些情况:

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

  • getBaseContext() 提供活动背景.

  • getApplication() 提供应用背景.

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

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


Mal*_*asz 6

我想知道为什么不对它支持的每个操作使用应用程序上下文。最后,它降低了内存泄漏的机会,并且减少了对getContext()或getActivity()的空检查(使用注入的应用程序上下文或通过Application的静态方法获取时)。像Hackborn女士所说的仅在需要时才使用Application Context的声明,在没有解释原因的情况下似乎对我没有说服力。但是,似乎我发现了一个失败的原因:

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

因为不能保证下表中描述的由Application Context支持的所有操作都可以在所有Android设备上使用! 在此处输入图片说明