背景,什么上下文?
上下文类型
并非所有上下文实例都创建相同。根据Android的应用程序组件,您可以访问的上下文略有不同:
应用程序 -在的英文应用程序进程中运行的单译文实例它可以通过诸如来自活动或服务的getApplication()方法状语从句:来自上下文的其他对象的getApplicationContext()来访问。无论访问何处或如何访问,您将始终从您的进程中收到相同的实例。
活动/服务 - 从实现相同API的ContextWrapper 继承,但代理所有的方法调用到一个隐藏的内部上下文实例,也称为其基础上下文。无论何时框架创建一个新的活动或服务实例,它还会创建一个新的ContextImpl实例来执行任何组件将包装的所有重大改进。每个活动或服务及其相应的基础上下文是每个实例唯一的。
广播接收器 -不是本身一个上下文,但 每次新的广播事件展示进入时 ,框架都会在的onReceive()中 传递一个上下文这个实例是一个。ReceiverRestrictedContext,其中两个主要功能被禁用; 调用registerReceiver()和bindService()。BroadcastReceiver.onReceive()中不允许使用这两个功能。每次接收器处理广播时,递交给它的上下文都是一个新的实例。
ContentProvider - 也不是一个上下文,但在创建时可以通过getContext()访问。如果ContentProvider在本地运行到调用者(即同一个应用程序进程),那么这将实际上返回相同的应用程序单例。但是,如果两者处于单独的进程中,则这将是一个新创建的实例,表示提供程序正在运行的程序包。
保存参考
需要我们解决的第一个问题来自于在对象或类中保存对上下文的引用,该对象或类的生命周期超出了您保存的实例的生命周期。例如,一个创建³³需要上下文来加载资源或访问的ContentProvider的定制单例,并保存对该单例例当前活动或服务的引用。
坏单身人士
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public
class
CustomManager
{
private
static
CustomManager
sInstance
;
public
static
CustomManager
getInstance
(
Context
context
)
{
if
(
sInstance
==
null
)
{
sInstance
=
new
CustomManager
(
context
)
;
}
return
sInstance
;
}
private
Context
mContext
;
private
CustomManager
(
Context
context
)
{
mContext
=
context
;
}
}
|
这里的问题是我们不知道上下文来自哪里,如果最终成为一个活动或一个服务,那么对对象的引用是不安全的这是一个问题,因为单例是由封闭类中的单个静态引用来管理的。这意味着我们的对象以及引用它的所有其他对象永远不会被垃圾回收。如果这个上下文的英文一个活动,我们将在内存中有效地将所有视图和其他可能与之相关的大对象保留在内存中; 造成泄漏
为了防止这种情况,我们修改单例以始终引用应用程序上下文:
更好的单身人士
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public
class
CustomManager
{
private
static
CustomManager
sInstance
;
public
static
CustomManager
getInstance
(
Context
context
)
{
if
(
sInstance
==
null
)
{
//Always pass in the Application Context
sInstance
=
new
CustomManager
(
context
.
getApplicationContext
(
)
)
;
}
return
sInstance
;
}
private
Context
mContext
;
private
CustomManager
(
Context
context
)
{
mContext
=
context
;
}
}
|
我们现在的上下文来自哪里,因为我们所持有的参考是安全的。应用程序上下文本身就是一个单例,因此我们不会通过创建另一个静态引用来泄露任何内容。另一个很好的例子就是在运行的后台线程或待处理程序内部保存对上下文的引用。
为什么那么我们不能总是只引用应用程序的上下文呢?把中间人从公式中解脱出来,不用担心造成泄漏?正如我在导言中所提到的,的英文答案因为一个上下文不等于另一个。
上下文功能
您可以使用给定的上下文对象可以采取的常见操作。它取决于最初来自哪里‧ 下面的英文一个应用程序将接收到上下文的通用位置的表,并且在每种情况下它对以下方面是有用的:
应用 | 活动 | 服务 | 内容提供商 | BroadcastReceiver | |
---|---|---|---|---|---|
显示对话框 | 没有 | 是的 | 没有 | 没有 | 没有 |
开始活动 | NO 1 | 是的 | NO 1 | NO 1 | NO 1 |
布局通货膨胀 | NO 2 | 是的 | NO 2 | NO 2 | NO 2 |
开始服务 | 是的 | 是的 | 是的 | 是的 | 是的 |
绑定到服务 | 是的 | 是的 | 是的 | 是的 | 没有 |
发送广播 | 是的 | 是的 | 是的 | 是的 | 是的 |
注册BroadcastReceiver | 是的 | 是的 | 是的 | 是的 | 没有3 |
加载资源值 | 是的 | 是的 | 是的 | 是的 | 是的 |
- 一个应用程序可以从这里开始一个活动,但它需要创建一个新的任务。这可以适应具体的用例,但是可以在你的应用程序中创建非标准的堆栈行为,通常不推荐或认为是良好做法。
- 这是合法的,但通货膨胀将使用您正在运行的系统的默认主题,而不是应用程序中定义的。
- 如果接收者为空,用于获取Android 4.2及更高版本上的粘性广播的当前值。
用户界面
从上表可以看出,应用程序上下文没有适合处理的功能有很多; 所有这些都与使用UI相关。实际上,处理与UI相关联的所有任务的唯一实现是活动; 其他实例在所有类别中几乎相同
幸运的是,这三个动作是一个应用程序在一个活动范围之外没有任何地方做的事情; 这几乎就像框架是按目的的设计的,尝试显示通过引用应用程序上下文创建的对话框,或者从应用程序上下文启动活动时会抛出异常并使用程序崩溃,这是一个强有力的指标。
不太明显的问题是布局膨胀。如果阅读你我的求最后一张布局通货膨胀,你已经知道这可能是一个微妙的过程与一些隐藏的行为;使用正确的上下文。到链接另一个行为虽然框架不会抱怨,并从返回一个完美的视图层次LayoutInflater与应用程序上下文创建的,从你的应用程序中的主题和风格不会在过程中考虑。这是因为活动是清单中定义的主题实际附加的唯一上下文。任何其他实例将使用系统默认主题来充实您的视图,导致您可能没有想到的显示输出。
这些规则的交点
总之,有人会得出这两个规则相冲突的结论。在应用程序的当前设计中有一个案例,其中必须保存长期参考,并且我们必须保存一个活动,因为我们要完成的任务包括操纵UI。如果是这样,我会敦促你重新考虑你的设计,因为这将是一个反对框架的课本实例。
拇指规则
在大多数情况下,请使用您正在使用的封闭组件中直接可用的上下文。只要该引用不超出该组件的生命周期,就可以安全地对其进行引用。一旦您需要从超出您的“活动”或“服务”的对象中保存对“ 上下文”的引用,即使临时将该保存的引用切换到应用程序上下文。
对于未来的见解和教程,请在下面的意见下面订阅我们的通讯。