活动上下文和应用程序上下文的区别

270

这让我很困惑,我正在使用Android 2.1-r8 SDK:

ProgressDialog.show(getApplicationContext(), ....);

并且也在

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

使用getApplicationContext()会导致ProgressDialogToast崩溃....这让我想到一个问题:

尽管都带有“Context”这个词,但活动上下文和应用程序上下文之间的实际区别是什么?


这是我找到的内容:https://dev59.com/GHI_5IYBdhLWcg3wBuRs.... - t0mm13b
14
这应该有助于澄清一些事情:背景,什么背景? - Etienne Lawlor
可能是何时调用Activity Context或Application Context?的重复问题。 - n611x007
7个回答

286
它们都是 Context 的实例,但应用程序实例与应用程序的生命周期相关联,而 Activity 实例与 Activity 的生命周期相关联。因此,它们可以访问有关应用程序环境的不同信息。
如果您在getApplicationContext文档中阅读,它指出只有在需要一个生命周期独立于当前上下文的上下文时才应使用该函数。这在您的示例中都不适用。
Activity 上下文可能包含有关当前 Activity 必要信息以完成这些调用。如果您显示确切的错误消息,可能能够指出它需要什么。
但一般情况下,请使用 Activity 上下文,除非您有充分的理由不使用。

2
当我使用getApplicationContext时,出现了'java.lang.reflect.InvocationTargetException'错误,有趣的是,当我改用this时,它没有崩溃并按预期工作...所以如果它们都是Context实例,为什么一个不起作用而另一个却可以?希望这些信息对其他人有所帮助... :) 感谢您的快速回答... - t0mm13b
2
我需要看到完整的异常堆栈跟踪才能发表任何意见。但是,正如我所说,上下文实例具有不同的信息。 显然,在屏幕上显示对话框或烤面包片需要关于Activity的信息,只有Activity实例才有。 - Cheryl Simon
88
除非有好的理由(例如用于对话框或 Toast),否则我建议使用应用程序上下文(app context)。在不同情况下使用活动上下文(activity context)很容易遇到内存泄漏问题,所以最好保险起见使用应用程序上下文。 :) 参考:http://android-developers.blogspot.com/2009/01/avoiding-memory-leaks.html - Dori
11
Dave Smith发表了一篇非常好的博客文章,以便更好地理解上下文的使用,点击这里查看。确保您也阅读评论! - ChrLipp
那么,将与用户界面无关的系统服务传递给我的应用程序代码类可能是一个好理由吗?我有一个单例类作为我的主要应用程序类(不是来自Android SDK的Application类的扩展类,只是我的应用程序GUI独立代码),并将活动上下文传递给单例实例以访问PackageManager和其他类似服务。使用getApplicationContext()是否更好,以避免销毁活动的问题? - Adrián Pérez
1
事实上,即使是 Dianna Hackborn 也建议使用活动上下文。https://dev59.com/3m435IYBdhLWcg3wxC9p#5228494 但她似乎自己也不完全确定这一点。 - JacksOnF1re

242

我发现这个表格对于决定何时使用不同类型的上下文非常有用:

输入图像描述 here

  1. 应用程序可以从这里启动活动,但需要创建一个新任务。 这可能适用于特定用例,但可能会在您的应用程序中创建非标准的返回堆栈行为,一般不建议或被认为是不良实践。
  2. 这是合法的,但将使用在您运行的系统上默认的主题进行膨胀,而不是您的应用程序中定义的主题。
  3. 如果接收器为null,则允许在Android 4.2及以上版本中使用,这用于获取粘性广播的当前值。

8
文章存档 https://web.archive.org/web/20150329210012/https://possiblemobile.com/2013/06/context/ - nmu
获取资源怎么样?我认为你最好将其添加到你的表格中。你可以使用应用程序上下文访问资源。 - Amir Ziarati
我们可以从应用程序上下文开始活动。 - Duy Phan
文章也可以在这里找到:https://wundermanthompsonmobile.com/2013/06/context/ - Lifes

39

显然这是API设计上的不足。首先,Activity Context和Application context是完全不同的对象,因此在使用context参数的方法中应该直接使用ApplicationContext或者Activity,而不是使用父类Context。 其次,文档应该明确指定要使用哪个上下文对象。


36
完全同意。谷歌在这件事上失误了。这是一团糟。 - Søren Boisen
1
@SørenBoisen Android SDK 是一团糟。 - CommonSenseCode
1
他们意识到了问题的严重性,我相信他们正在努力尽可能地解决。 - pasignature

17
我认为原因是 ProgressDialog 附加到支持 ProgressDialog 的活动上,因为对话框在活动销毁后不能保留,所以需要传递this(ActivityContext),该上下文随着活动一起被销毁,而 ApplicationContext 即使在活动销毁后仍然存在。

4
当你直接从主屏幕启动应用程序时与通过共享意图从另一个应用程序启动应用程序时,你可以看到两个上下文之间的差异。
这里提供了一个实际的例子,说明了@CommonSenseCode所提到的“非标准返回堆栈行为”的含义:
假设你有两个相互通信的应用程序,App1和App2。
从launcher启动App2:MainActivity。然后从MainActivity启动App2:SecondaryActivity。在那里,使用活动上下文或应用程序上下文,两个活动都存在于同一个任务中,这是可以的(假定你使用了所有标准的启动模式和意图标记)。你可以通过后退按钮返回到MainActivity,并且在最近使用的应用程序中只有一个任务。
现在假设你在App1中,并使用共享意图(ACTION_SEND或ACTION_SEND_MULTIPLE)启动App2:MainActivity。然后从那里尝试启动App2:SecondaryActivity(始终使用所有标准的启动模式和意图标记)。
发生的情况如下:
如果在Android < 10上使用应用程序上下文启动App2:SecondaryActivity,则不能在同一个任务中启动所有活动。我已经尝试过android 7和8,SecondaryActivity总是在一个新任务中启动(我猜这是因为App2:SecondaryActivity是使用App2应用程序上下文启动的,但你来自App1,没有直接启动App2应用程序。在底层,Android可能会识别到这一点,并使用FLAG_ACTIVITY_NEW_TASK)。这可能是好的或坏的,具体取决于你的需求,对于我的应用程序而言是不好的。 在Android 10上,应用程序会崩溃并显示以下消息:“Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?”。因此,在Android 10上使其正常工作,你必须使用FALG_ACTIVITY_NEW_TASK,并且不能在同一个任务中运行所有活动。 如你所见,不同版本的Android之间的行为是不同的,很奇怪。
如果使用活动上下文启动App2:SecondaryActivity,则一切都很顺利,你可以在同一个任务中运行所有活动,从而形成线性返回堆栈导航。
我希望我添加了一些有用的信息。

3

我认为当所有需要显示屏幕的东西(按钮、对话框、布局...)时,我们必须使用上下文活动,而不需要显示或处理屏幕的所有东西(toast、服务电话、联系人...)我们可以使用应用程序上下文。


3

如果您需要与具有全局范围的上下文相关联的内容,请使用getApplicationContext()。

如果使用Activity,则新的Activity实例将具有一个引用,该引用具有对旧Activity的隐式引用,因此旧Activity无法进行垃圾回收。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接