說明:基於API 26的原始碼分析
1. 類圖
Context: 是一個抽象類。
ContextImpl: 是Context真正的實現類。
ContextWrapper: 繼承Context,是一個包裝類,有一個mBase的成員變數,mBase是Context型別,Context抽象方法都是由mBase實現的。子類通過呼叫attachBaseContext方法替換mBase成員變數。
Application, Activity, Service都是繼承ContextWrapper,它們的真正的實現都是ContextImpl例項,
通過attachBaseContext方法把ContextImpl例項賦值給mBase。
所以在activity或者application中常用的方法,例如 :
- getSharedPreferences(String name, int mode)
- startActivity
- sendBroadcast
- 等等等
上述的常用的方法真正實現都是在ContextImpl
2. 原始碼分析
2.1 Application建立為例
Application的例項從ActivityThread的handleBindApplication(),再到LoadedApk的makeApplication()建立的。
第一步:LoadedApk的makeApplication方法
cl是ClassLoader, appClass是Application的全類名, 通過ContextImpl.createAppContext建立一個ContextImpl例項,把ContextImpl例項、cl、appClass傳到mInstrumentation.newApplication方法建立Application例項。
第二步: Instrumentation的newApplication方法
public Application newApplication(ClassLoader cl, String className, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
return newApplication(cl.loadClass(className), context);
}
static public Application newApplication(Class<?> clazz, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
Application app = (Application)clazz.newInstance();
app.attach(context);
return app;
}
//Application的attach方法:
/* package */ final void attach(Context context) {
attachBaseContext(context);
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
複製程式碼
先通過classLoader的loadClass(className)獲取application的class,再通過clazz.newInstance()建立Application例項,接著呼叫app.attach(context)方法完成初始化。 Application的attach方法裡是通過attachBaseContext(context), 把第一步建立的ContextImpl例項賦值給ContextWrapper的mBase成員變數。 到此Application例項建立就完成啦。
2.2 Activity建立為例
Activity建立和Application的建立類似,在ActivityThread的performLaunchActivity方法裡
第一步:ActivityThread的performLaunchActivity方法
通過creatBaseContextForActivity方法建立ContextImpl例項,接著通過mInstrumentation.newActivity建立Activity例項,Activity例項通過classloader,載入className,呼叫clazz的newInstance方法建立。再接著呼叫activity.attach方法完成初始化。
第二步:Activity的attach方法
Activity的attach方法裡是通過attachBaseContext(context), 把第一步建立的ContextImpl例項賦值給ContextWrapper的mBase成員變數。 到此Activity例項建立就完成啦。
2.3 Service建立為例
Service裡的Context建立和Activity差不多
第一步:定位到ActivityThread的handleCreateService方法
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
Application app = packageInfo.makeApplication(false, mInstrumentation);
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
service.onCreate();
複製程式碼
呼叫ContextImpl的createAppContext()建立ContextImpl,呼叫setOuterContext()把service儲存在ContextImpl的mOuterContext成員變數中,呼叫service.attach(),再呼叫service.onCreate()
第二步: Service的attach方法
public final void attach(
Context context,
ActivityThread thread, String className, IBinder token,
Application application, Object activityManager) {
attachBaseContext(context);
mThread = thread;
mClassName = className;
mToken = token;
mApplication = application;
mActivityManager = (IActivityManager)activityManager;
mStartCompatibility = getApplicationInfo().targetSdkVersion
< Build.VERSION_CODES.ECLAIR;
}
複製程式碼
通過attachBaseContext(context), 把第一步建立的ContextImpl例項賦值給ContextWrapper的mBase成員變數。
3. 總結
ContextWrapper繼承Context。Application, Activity, Service都是繼承ContextWrapper,它們的真正的實現都是ContextImpl例項,通過attachBaseContext方法把ContextImpl例項賦值給mBase。Context裡抽象方法真正實現都是在ContextImpl裡。
還有一個共同點:
- Application 或者Activity建立後都會呼叫 contextImpl.setOutContext(context),把Application 或者Activity例項儲存在ContextImpl的mOuterContext成員變數中