Context 到底是什么?
如果面试官问这样一个问题,你该如何回答呢?
这里希望通过这篇文章,梳理一下,然后给自己一个**Context 到底是什么?**的解答。
谷歌官方API上这样写道:
Interface to global information about an application environment. This is an abstract class whose implementation is provided by the Android system. It allows access to application-specific resources and classes, as well as up-calls for application-level operations such as launching activities, broadcasting and receiving intents, etc.
来自:
https://developer.android.com/reference/android/content/Context
翻译一下:
Context是一个关于application environment(应用环境)的全局信息入口。Context是一个抽象类,由Android系统提供Context的实现。Context允许访问应用程序特定的资源和类,以及调用应用程序级操作,如启动activity、发送广播、接收 intent 等
这么看Context是:
一个关于App的全局信息入口。Context的作用是访问应用资源和类、启动Activity、发送广播、接收 intent 等。
Context既然是一个抽象类,那我们就来看一下它的实现子类。
Android源码(android-25)中,它的子类关系图如下:
通过查看源码,我们得知:
到这里,觉得:Context就是一个提供App内资源访问的全局信息入口。
看到Context 都没弄明白,还怎么做 Android 开发?中有这么一句话,觉得很有意思,写在这里:
一个Activity就是一个Context,一个Service也是一个Context。
Android程序员把“场景”抽象为Context类,他们认为用户和操作系统的每一次交互都是一个场景,比如打电话、发短信,这些都是一个有界面的场景;还有一些没有界面的场景,比如后台运行的服务(Service)。
一个应用程序可以认为是一个工作环境,用户在这个环境中会切换到不同的场景,这就像一个前台秘书,她可能需要接待客人,可能要打印文件,还可能要接听客户电话,而这些就称之为不同的场景,前台秘书可以称之为一个应用程序。
既然Activity、Application、Service 都是一个Context对象,Context可以提供资源的访问。那么如何保证,在Activity、Service中获取到的资源为同一份资源呢?
这里我们先查一下ContextImpl的源码:
源码地址:
https://www.androidos.net.cn/android/7.1.1_r28/xref/frameworks/base/core/java/android/app/ContextImpl.java
@Override
public Resources getResources() {
return mResources;
}
mResources
获取的,下边看一下mResources对象的创建。在ContextImpl构造方法中发现:
private ContextImpl(ContextImpl container, ActivityThread mainThread,
LoadedApk packageInfo, IBinder activityToken, UserHandle user, int flags,
Display display, Configuration overrideConfiguration, int createDisplayWithId) {
mOuterContext = this;
// 这里省略部分代码...
// 构造方法中创建了一个ResourcesManager对象
mResourcesManager = ResourcesManager.getInstance();
final int displayId = (createDisplayWithId != Display.INVALID_DISPLAY)
? createDisplayWithId
: (display != null) ? display.getDisplayId() : Display.DEFAULT_DISPLAY;
CompatibilityInfo compatInfo = null;
if (container != null) {
compatInfo = container.getDisplayAdjustments(displayId).getCompatibilityInfo();
}
if (compatInfo == null) {
compatInfo = (displayId == Display.DEFAULT_DISPLAY)
? packageInfo.getCompatibilityInfo()
: CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
}
Resources resources = packageInfo.getResources(mainThread);
if (resources != null) {
if (displayId != Display.DEFAULT_DISPLAY
|| overrideConfiguration != null
|| (compatInfo != null && compatInfo.applicationScale
!= resources.getCompatibilityInfo().applicationScale)) {
if (container != null) {
// This is a nested Context, so it can't be a base Activity context.
// Just create a regular Resources object associated with the Activity.
resources = mResourcesManager.getResources(
activityToken,
packageInfo.getResDir(),
packageInfo.getSplitResDirs(),
packageInfo.getOverlayDirs(),
packageInfo.getApplicationInfo().sharedLibraryFiles,
displayId,
overrideConfiguration,
compatInfo,
packageInfo.getClassLoader());
} else {
// This is not a nested Context, so it must be the root Activity context.
// All other nested Contexts will inherit the configuration set here.
resources = mResourcesManager.createBaseActivityResources(
activityToken,
packageInfo.getResDir(),
packageInfo.getSplitResDirs(),
packageInfo.getOverlayDirs(),
packageInfo.getApplicationInfo().sharedLibraryFiles,
displayId,
overrideConfiguration,
compatInfo,
packageInfo.getClassLoader());
}
}
}
// ResourcesManager 通过getResources方法创建了Resources对象
mResources = resources;
// 这里省略部分代码...
}
通过以上代码,我们得知:
//
private static ResourcesManager sResourcesManager;
//
public static ResourcesManager getInstance() {
synchronized (ResourcesManager.class) {
if (sResourcesManager == null) {
sResourcesManager = new ResourcesManager();
}
return sResourcesManager;
}
}
查看ResourcesManager
源码,发现ResourcesManager
是一个单例,因此Activity、Application、Service通过ResourcesManager
获取的资源,为同一资源。