Context在Android中表示上下文对象,也是开发中常常使用的类,如资源的获取、View的建立、窗口建立添加等,在Android的四大组件中也随处可见Context的身影,也是Context使用的主战场,能够说Context的重要程度非通常类可比,但不少人对其内部结构并非很熟悉,最基本的将、常常使用的却不必定熟悉,是否是有点灯下黑的感受,本篇文章就针对context在Android中的使用进行学习;java
按照实际开发的使用场景来讲,Context通常分两种:android
由Android进阶知识树——Android四大组件启动过程知道,程序中Activity在启动过程会执行到ActivityThread.performLaunchActivity()中,在performLaunchActivity()中完成Activity主要的建立和初始化过,程其中就包含建立Application对象app
Application app = r.packageInfo.makeApplication(false, mInstrumentation); //建立了Application并调用onCreate()初始化
复制代码
public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) {
appClass = "android.app.Application";
try {
java.lang.ClassLoader cl = getClassLoader();
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
app = mActivityThread.mInstrumentation.newApplication( //调用Instrumentation建立Application
cl, appClass, appContext);
appContext.setOuterContext(app);//
}
return app;
}
复制代码
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0,
null);
context.setResources(packageInfo.getResources());
return context;
}
复制代码
在上面方法中直接建立了ContextImpl对象,并初始化ContextImpl对象中的Resource实例,在建立了ContextImpl后调用了 mInstrumentation.newApplication()方法,传入appClass、ClassLoader、appContext对象;ide
Application app = getFactory(context.getPackageName())
.instantiateApplication(cl, className);
app.attach(context);
//Application.attach()
final void attach(Context context) {
attachBaseContext(context);
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
复制代码
在newApplication()中先使用ClassLoader和appClass建立了Application对象,而后调用attach()将Application与ContextImpl对象进行绑定,attach()中调用了父类ContextWrapper中的attachBaseContext()方法函数
protected void attachBaseContext(Context base) {
mBase = base;
}
复制代码
通过上面的过程,就可将建立的ContexImpl对象赋值在Application中的mBase对象,在程序使用中便可直接经过mBase调用ContexImpl中的方法;学习
开发中使用getApplicaitonContext()获取程序中的Application的Context对象,在getApplicaitonContext是ContextWrapper中方法,其内部直接调用父类的mBase方法获取对象,此处的mBase就是上面赋值的ContextImpl,在ContextImpl.getApplicationContext()中根据mPackageInfo获取建立的Application对象;this
@Override
public Context getApplicationContext() {
return mBase.getApplicationContext();
}
// ContextImpl
@Override
public Context getApplicationContext() {
return (mPackageInfo != null) ?
mPackageInfo.getApplication() : mMainThread.getApplication();
}
//最终返回的是在LoadedApk.makeApplication中建立的mApplication
Application getApplication() {
return mApplication;
}
复制代码
从Application的建立和获取过程可知道,在建立Application对象前建立了ContextImpl对象,在Application对象建立后调用attach()赋值父类的mBase,将Applicaiton和ContextImpl关联起来,在使用时经过mBse查找系统的Applicaiton并返回。spa
由Activity的启动过程知道performLaunchActivity()中不只完成Application中Context的建立过程,还实例化了Activity对象而且建立了Activity中的Context.net
ContextImpl appContext = createBaseContextForActivity(r);
activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent);
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback);
复制代码
下面这对前面的过程逐步分析:插件
private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
ContextImpl appContext = ContextImpl.createActivityContext(
this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);
return appContext;
}
复制代码
final void attach(Context context, ActivityThread aThread, ...... Window window, ActivityConfigCallback activityConfigCallback) {
attachBaseContext(context);
}
复制代码
在attach()中一样调用父类的attachBaseContext()方法,由上面的分析知道attachBaseContext()赋值了父类的mBase对象,因此在Activity中调用context的方法其真实调用的就是建立的ContextImpl对象;
public Context getBaseContext() {
return mBase; //直接返回前面赋值的mBase,即ContextImpl对象
}
复制代码
由Android进阶知识树——Android四大组件启动过程知道,Service的启动过程当中会执行的ActivityThread中的handleCreateService()方法,handleCreateService()中进行了一些列对象的建立和初始化:
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
复制代码
在handleCreateService()中和Application中建立过程同样,先调用createAppContext()建立ContextImpl对象,而后调用Service的attach()方法
public final void attach( ...... Application application, Object activityManager) {
attachBaseContext(context);
}
复制代码
Service的attach()中一样调用父类的attachBaseContext()方法进行父类mBase的初始化,使用时也同样调用ContextImpl中的方法。
public Context getBaseContext() {
return mBase; // 获取mBase
}
复制代码
由Android进阶知识树——ContentProvider使用和工做过程详解一文知道,在AMS启动程序进程后就会进行ContentProvider操做,具体在ActivityThread中的handleBindApplication()中,handleBindApplication中有如下几行代码
private void handleBindApplication(AppBindData data) {
final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);//1
installContentProviders(app, data.providers);//2
}
复制代码
在注释1处和Application中同样调用createAppContext()建立ContentImpl对象,而后调用installContentProviders()执行ContentProvider初始化
localProvider = packageInfo.getAppFactory().instantiateProvider(cl, info.name);//1
provider = localProvider.getIContentProvider();
localProvider.attachInfo(c, info); //
复制代码
注释1中使用ClassLoader建立ContentProvider对象,在注释2中调用attachInfo()方法,传入的第一个参数就是上面建立的appContext对象;
private void attachInfo(Context context, ProviderInfo info, boolean testing) {
if (mContext == null) {
mContext = context; //赋值mContext
}
}
复制代码
public final @Nullable Context getContext() {
return mContext; // 直接返回保存的Context
}
复制代码
在BroadCast Receiver的回调方法onReceive()的参数中会回传Context对象,因此广播中的Context使用主要是针对此处,由 Android进阶知识树——Android四大组件启动过程知道广播的发送最终执行到LoadedApk.ReceiverDispatcher.performReceive()中,而后执行Runnable中方法完成onReceiver()的回调
public final Runnable getRunnable() {
return () -> {
final BroadcastReceiver receiver = mReceiver; //执行receiver的onReceiver()
receiver.setPendingResult(this);
receiver.onReceive(mContext, intent); // 传入mContext
}
}
复制代码
那么此处的context是从哪来的呢?跟随mContext查找会发现它是ReceiverDispatcher中的属性,在ReceiverDispatcher的构造函数中完成初始化
final Context mContext;
ReceiverDispatcher(BroadcastReceiver receiver, Context context,
Handler activityThread, Instrumentation instrumentation,
boolean registered) {
mContext = context; //初始化mContext
}
复制代码
熟悉四大组件启动过程的知道,ReceiverDispatcher是在注册广播时建立的,由于广播多是跨进程的因此在ReceiverDispatcher中保存Binder和Receiver的对应关系,具体的注册在ContextImpl中,最终调用ContextImpl.registerReceiverInternal(),在registerReceiverInternal()中调用getReceiverDispatcher()建立ReceiverDispatcher对象
rd = mPackageInfo.getReceiverDispatcher(
resultReceiver, getOuterContext(), scheduler,
mMainThread.getInstrumentation(), false);
final Context getOuterContext() {
return mOuterContext;
}
复制代码
在getReceiverDispatcher()中传入getOuterContext(),getOuterContext()获取的是ContentImpl的属性mOuterContext,mOuterContext在Activity的初始化过程当中被赋值;
appContext.setOuterContext(activity); //传入Activity对象
复制代码
到此,关于Context的继承关系和在Android系统中的使用到此就介绍完毕了,关于这类知识的使用在开发中或许使用不多,但在插件化过程当中须要替换系统资源时就必须了解其内部原理和关系了。