從應用場景的角度來講,他是一個場景,一個用戶與系統交互的過程.好比當你看短信時,場景包括短信的頁面,以及隱藏在後面的數據java
提到頁面,咱們應該可以聯想到 Activityapp
沒錯,Activity,Service都是一個Contextide
從JAVA語言角度來講,Context是一個抽象類,抽象類中包含了Application環境的一些函數,設計角度而言,Context僅提供某些功能, extends 纔是類的本質,即 Activity 的本質是一個 Context ,其所實現的其餘接口只是爲了擴充 Context 的功能而已,擴充後的類稱之爲 Activity 或 Service函數
Context個數=1 + Activity個數 + Service個數this
在博客 ActivityThread.main過程 中分析中能夠知道, handleBindApplication 函數中會調用 makeApplicationspa
makeApplication會建立Application以及建立 ContextImpl設計
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
複製代碼
這裏的this是 LoadedApk 對象,該對象是在 handleBinderApplication 中賦值code
data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
複製代碼
在該函數中,會根據 AppBindData(handleBinderApplication中的參數) 中的ApplicationInfo的mPackageName建立一個PackageInfo對象並保存爲ActivityThread類的全局對象orm
顯然,一個應用程序中全部Activity或者Application或Servie,他們的mPackageName是同樣的,即爲包名,所以ActivityThread只會有一個全局的PackageInfo對象對象
在 newApplication的函數中會調用 Application 的 attach
final void attach(Context context) {
attachBaseContext(context);
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
複製代碼
查看 attachBaseContext
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
複製代碼
這個mBase就是 ContextWrapper 中的 Context
在 Launcher啓動流程 的分析中能夠知道,handleLaunchActivity 會調用到 performLaunchActivity,該函數會調用 createBaseContextForActivity
private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
final int displayId;
...
ContextImpl appContext = ContextImpl.createActivityContext(
this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);
...
return appContext;
}
複製代碼
createActivityContext 中的 packageInfo 信息和上小節分析的流程基本一致,他也是全局的
static ContextImpl createActivityContext(ActivityThread mainThread, LoadedApk packageInfo, ActivityInfo activityInfo, IBinder activityToken, int displayId, Configuration overrideConfiguration) {
...
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, activityInfo.splitName,
activityToken, null, 0, classLoader);
...
return context;
}
複製代碼
建立Context完成後,調用 activity 的 attach 函數
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);
複製代碼
attach 函數中作了不少的賦值操做,其中 attachBaseContext 的函數和Application的 attachBaseContext 中做用一致,把context賦值給 ContextWrapper 的 mBase
:::danger 筆記 所以,當咱們翻閱Activity源碼,看到mBase時,就應該去找 ContextImpl 裏的方法 :::
Service的啓動和Activity相似,最終一樣會調用到ActivityThread裏的函數,爲 scheduleCreateService,接着調用 handleCreateService
在 handleCreateService 中會建立Context
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();
複製代碼
Context的建立方式和Application一致,一樣在建立後會調用 attach 進行一些賦值操做,一樣也有以前分析的 mBase
不一樣Context子類中PackageInfo對象來源
類名 | 遠程數據類 | 本地數據類 | 賦值方式 |
---|---|---|---|
Application | ApplicationInfo | AppBindData | getPackageInfoNoCheck |
Activity | ActivityInfo | ActivityClientRecord | getPackageInfo |
Service | ServiceInfo | CreateServiceData | getPackageInfoNoCheck |
參考書籍: Android內核剖析