文章目录
对于Application,Activity和Service这几个类,我们是很[熟悉]的。确实[熟悉],作为App开发这基本都要面对这几个类。
比较好奇的朋友会发现,他们都拥有Context,但他们的Context有似乎有一点点的不同。今天有空,根据网上大佬的步伐,在这里简单记录一下。
正文
Context的使用场景
使用Context调用方法,比如启动Activity、访问资源、调用系统级服务等。
调用方法时传入Context,比如弹出Toast、创建Dialog等。
Context意为[上下文],也是Application,Activity和ServiceContext的祖先类。
Application -> ContextWrapper -> Context; Activity -> ContextThemeWrapper -> ContextWrapper -> Context Service -> ContextWrapper -> Context
或者看图,图上更详细

通过源码发现,Context其实也不干活的,具体干活的是ContextImpl。
今天就介绍一下Application的Context。
Application的Context
在Application中,经常通过如下获取Context
Context context = getApplicationContext();
getApplicationContext()是ContextWrapper中的类
ContextWrapper.java
@Override public Context getApplicationContext() { return mBase.getApplicationContext(); }
竟然调用的是mBase的
Context mBase;
Context.java
public abstract Context getApplicationContext();
啊哈,竟然是抽象方法。那就找它的儿子类们。
从上面继承图中看到Context的儿子类有ContextWrapper和ContextImpl,我们是从ContextWrapper中跟入的,没有实现,那就是ContextImpl进行了实现。
ContextImpl.java
@Override public Context getApplicationContext() { return (mPackageInfo != null) ? mPackageInfo.getApplication() : mMainThread.getApplication(); }
从上面看的话,如果mPackageInfo不为null,就通过mPackageInfo的方法总获取,否则就通过mMainThread的方法中获取。
final @NonNull LoadedApk mPackageInfo; final @NonNull ActivityThread mMainThread;
我们分别看看mPackageInfo和mMainThread初始化。
ContextImpl()
private ContextImpl(@Nullable ContextImpl container, @NonNull ActivityThread mainThread, @NonNull LoadedApk packageInfo, @Nullable String splitName, @Nullable IBinder activityToken, @Nullable UserHandle user, int flags, @Nullable ClassLoader classLoader) { //略 //mMainThread赋值 mMainThread = mainThread; //略 //mPackageInfo赋值 mPackageInfo = packageInfo; //略 }
从上面看,mPackageInfo和mMainThread赋值都在这里,但调用new ContextImpl()方法确实很多,都在ContextImpl.java中。
1. createAppContext(); 2. createActivityContext(); 3. createSystemUiContext(); 4. createSystemContext(); 等
根据参考文和我们之前的源码分析《》,知道ActivityThread.java中会去创建Application。
ActivityThread.java
Application的创建是在H发送BIND_APPLICATION中进行创建的。
handleMessage()
public void handleMessage(Message msg) {
switch (msg.what) {
case BIND_APPLICATION:
AppBindData data = (AppBindData)msg.obj;
//处理和绑定
handleBindApplication(data);
break;
//略
}
}
handleBindApplication()
private void handleBindApplication(AppBindData data) {
//略,[大部分不关注的略了]
Application app;
try {
//[重]创建Application
app = data.info.makeApplication(data.restrictedBackupMode, null);
//略
try {
//调用mInstrumentation的onCreate()
mInstrumentation.onCreate(data.instrumentationArgs);
}catch (Exception e) {
}
try {
//执行Application的onCreate()方法
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
}
} finally {
if (data.appInfo.targetSdkVersion < Build.VERSION_CODES.O_MR1
|| StrictMode.getThreadPolicy().equals(writesAllowedPolicy)) {
StrictMode.setThreadPolicy(savedPolicy);
}
}
//略
}
这里我们只关注Application的创建,也就是
app = data.info.makeApplication(data.restrictedBackupMode, null);
这里的data.info就是LoadedApk对象。
LoadedApk.java
makeApplication()
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
//第一次执行,这里为null,但再次进入这里就不会null啦
if (mApplication != null) {
return mApplication;
}
Application app = null;
//启动应用的Application包名
String appClass = mApplicationInfo.className;
if (forceDefaultAppClass || (appClass == null)) {
//如果为null,就赋值默认的
appClass = "android.app.Application";
}
try {
java.lang.ClassLoader cl = getClassLoader();
//略
//[重]创建appContext
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
//[重]创建Application
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
} catch ( e) {
//略
}
//赋值给mApplication
mApplication = app;
//略
return app;
}
先看appContext的创建
ContextImpl.java
createAppContext()
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
//packageInfo不为null
if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
//创建了Application的context
//也就是回到我们上面介绍的了,packageInfo不为null
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0,
null);
context.setResources(packageInfo.getResources());
return context;
}
至此,Application的Context已经创建了。
再看看Application的创建,既然创建了Application的Context,那需要跟Application进行绑定。
回到上面
//创建Application
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
调用的是Instrumentation的newApplication()方法
Instrumentation.java
newApplication()
public Application newApplication(ClassLoader cl, String className, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
//getPackageName()包名:com.biumall.image
//className类名:com.biumall.image.ImageApp
//具体看了一下,instantiateApplication()实现方式
//实例化了一个Application
Application app = getFactory(context.getPackageName())
.instantiateApplication(cl, className);
//[重]绑定了Application Context
app.attach(context);
return app;
}
Application.java
attach()
final void attach(Context context) {
//绑定到mBase中
attachBaseContext(context);
//赋值mLoadedApk
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
ContextWrapper.java
protected void attachBaseContext(Context base) {
//只能设置一次
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
mBase就是Application Context。
回到ContextImpl.java中,也就是上面的getApplicationContext()获取处。
ContextImpl.java
getApplicationContext()
@Override
public Context getApplicationContext() {
return (mPackageInfo != null) ?
mPackageInfo.getApplication() : mMainThread.getApplication();
}
中的mPackageInfo就是上面赋值的LoadedApk对象,不为null
# LoadedApk对象 mPackageInfo.getApplication()
LoadedApk.java
进入getApplication()
getApplication()
Application getApplication() {
return mApplication;
}
这里返回的mApplication就是在makeApplication()中创建的Application。
参考文章
《》
《Android进阶解密-刘望舒》
《Android内核剖析-柯元旦》
