有很多关于这两种背景的帖子......但我仍然没有把它弄得恰到好处
据我所知到目前为止:每个都是它的类的一个实例,这意味着一些程序员建议你尽可能频繁地使用 this.getApplicationContext()
,以免出现任何内存 . 这是因为另一个 this
(获取 Activity
实例上下文)指向每次用户倾斜手机或离开应用程序等时被销毁的 Activity
. 显然垃圾收集器(GC)没有捕获并因此使用记忆太多了..
但是,任何人都可以想出一些非常好的编码示例,使用 this
(获取当前 Activity
实例的上下文)是正确的,并且应用程序上下文将是无用的/错误的吗?
7 回答
getApplicationContext()
几乎总是错的 . Ms. Hackborn(以及其他)非常清楚,当您知道为什么使用getApplicationContext()
并且仅在需要使用getApplicationContext()
时才使用getApplicationContext()
.说实话,"some programmers"使用
getApplicationContext()
(或者getBaseContext()
,在较小程度上)因为他们的Java经验有限 . 它们实现了一个内部类(例如,OnClickListener
中的Button
为OnClickListener
)并且需要Context
. 他们使用getApplicationContext()
或getBaseContext()
来获取Context
对象,而不是使用MyActivity.this
来获取外部类'this
.只有当你知道自己需要
Context
才能使用getApplicationContext()
时,你可以使用getApplicationContext()
,这可能比你拥有的任何其他东西都要长 . 场景包括:如果您需要绑定到
Context
的东西,请使用getApplicationContext()
本身将具有全局范围 . 例如,我在WakefulIntentService
中使用getApplicationContext()
,用于服务的静态WakeLock
. 由于WakeLock
是静态的,并且我需要Context
来获取PowerManager
来创建它,因此使用getApplicationContext()
是最安全的 .当您从
Activity
绑定Service
时使用getApplicationContext()
,如果您希望通过onRetainNonConfigurationInstance()
在Activity
实例之间传递ServiceConnection
(即绑定句柄) . Android内部通过这些ServiceConnections
跟踪绑定,并保存对创建绑定的Contexts
的引用 . 如果从Activity
绑定,那么新的Activity
实例将具有对ServiceConnection
的引用,该引用具有对旧Activity
的隐式引用,并且旧的Activity
不能被垃圾回收 .一些开发人员使用
Application
的自定义子类作为他们自己的全局数据,他们通过getApplicationContext()
检索它们 . 这当然是可能的 . 我更喜欢静态数据成员,如果没有其他原因,你只能拥有一个自定义Application
对象 . 我使用自定义Application
对象构建了一个应用程序,发现它很痛苦 . Ms. Hackborn also agrees with this position .以下是无论何时何地不使用
getApplicationContext()
的原因:这不是一个完整的
Context
,支持Activity
所做的一切 . 你将尝试用这个Context
做的各种事情都会失败,mostly related to the GUI .如果来自
getApplicationContext()
的Context
保留在您不能清理的调用所创建的内容上,则可能会造成内存泄漏 . 使用Activity
,如果它保留了某些东西,一旦Activity
被垃圾收集,其他一切也会被淘汰 .Application
对象在您的进程的生命周期内保持不变 .我认为SDK网站上有很多文档记录很少,这就是其中之一 . 我要提出的主张是,似乎最好默认使用应用程序上下文,并且只在需要时才使用活动上下文 . 我见过你需要一个活动上下文的唯一地方是进度对话框 . SBERG412声称您必须使用活动上下文来提供Toast消息,但Android文档清楚地显示正在使用的应用程序上下文 . 由于Google的这个例子,我总是将应用程序上下文用于祝酒 . 如果这样做是错误的,那么谷歌就把球丢了 .
这里有更多的思考和评论:
对于Toast消息,Google Dev Guide使用应用程序上下文并明确说出要使用它:Toast Notifications
在Dev指南的对话框部分中,您会看到AlertDialog.Builder使用应用程序上下文,然后进度条使用活动上下文 . Google没有解释这一点 . Dialogs
使用应用程序上下文似乎是一个很好的理由,当您想要处理配置更改(如方向更改)时,您希望保留需要像Views这样的上下文的对象 . 如果你看这里:Run Time Changes使用活动上下文时要小心,这可能会造成泄漏 . 这可以通过具有要保留的视图的应用程序上下文来避免(至少写入's my understanding). In an app I'm,我打算使用应用程序上下文,因为我试图在方向更改上保留一些视图和其他内容,以及我仍然希望在方向上销毁和重新创建活动变化 . 因此,我必须使用应用程序上下文不会导致内存泄漏(请参阅Avoiding memory Leaks) . 对我而言,似乎有很多充分的理由使用应用程序上下文而不是活动上下文,对我来说,几乎看起来你会比活动上下文更频繁地使用它 . 经历过这种情况似乎已经完成了,并且已经看到过了 .
谷歌文档确实使得在大多数情况下使用应用程序上下文看起来非常好,并且实际上比在他们的示例中使用活动上下文更频繁(至少我见过的例子) . 如果使用应用程序上下文确实是个问题,那么谷歌真的需要更加重视这一点 . 他们需要说清楚,他们需要重做他们的一些例子 . 我不会完全归咎于没有经验的开发人员,因为权威(谷歌)真的让它看起来好像使用应用程序上下文不是问题 .
我使用此表作为何时使用不同类型的上下文的指导,例如 Application context (即:
getApplicationContext()
)和 activity context ,以及 BroadcastReceiver context :原始文章here了解更多信息 .
上下文有两种类型:
Application context 与应用程序相关联,并且在应用程序的整个生命周期中始终保持相同 - 它不会更改 . 因此,如果您正在使用Toast,则可以使用应用程序上下文甚至活动上下文(两者),因为Toast可以在应用程序中的任何位置显示,并且不会附加到特定窗口 . 但是有很多例外,一个例外是当您需要使用或传递活动上下文时 .
Activity context 与活动相关联,如果活动被销毁则可以销毁 - 单个应用程序可能有多个活动(很可能) . 有时你绝对需要活动上下文句柄 . 例如,如果启动新活动,则需要在其Intent中使用活动上下文,以便新的启动活动根据活动堆栈连接到当前活动 . 但是,您也可以使用应用程序的上下文来启动新活动,但是您需要将intent
Intent.FLAG_ACTIVITY_NEW_TASK
设置为intent以将其视为新任务 .让我们考虑一些情况:
MainActivity.this
指的是扩展Activity类的MainActivity上下文,但基类(activity)也扩展了Context类,因此它可用于提供活动上下文 .getBaseContext()
提供活动背景 .getApplication()
提供应用程序上下文 .getApplicationContext()
还提供应用程序上下文 .有关更多信息,请查看link .
应该使用Activity上下文与Application上下文的两个很好的例子是在显示Toast消息或内置Dialog消息时,因为使用Application上下文会导致异常:
要么
这两者都需要来自Activity上下文的信息,而这些信息并未在Application上下文中提供 .
应用程序上下文实时,直到您的应用程序仅存活,并且它不依赖于活动生命周期,但上下文保持对象长期存在 . 如果你临时使用的对象,那个时候使用 Application Context 和 Activity Context 是完全对应的应用程序上下文 .
我想知道为什么不为它支持的每个操作使用Application Context . 最后,它降低了内存泄漏的可能性,并且缺少对getContext()或getActivity()的空检查(当使用注入的应用程序上下文或通过Application中的静态方法获取时) . 声明,就像Ms. Hackborn仅在需要时使用应用程序上下文一样,在没有解释原因的情况下对我来说似乎并不令人信服 . 但似乎我找到了一个不合理的原因:
Because it's not guaranteed that all operations described as supported by Application Context in the table below will work on all Android devices!