理解Context
從應用場景的角度來說,他是一個場景,一個使用者與系統互動的過程.比如當你看簡訊時,場景包括簡訊的頁面,以及隱藏在後面的資料
提到頁面,我們應該能夠聯想到 Activity
沒錯,Activity,Service都是一個Context
從JAVA語言角度來說,Context是一個抽象類,抽象類中包含了Application環境的一些函式,設計角度而言,Context僅提供某些功能, extends 才是類的本質,即 Activity 的本質是一個 Context ,其所實現的其他介面只是為了擴充 Context 的功能而已,擴充後的類稱之為 Activity 或 Service
有多少Context
- Application一個Context
- 多少個Activity就有多少個Context
- 多少個Service就有多少個Context
Context個數=1 + Activity個數 + Service個數
Application的Context建立
在部落格ActivityThread.main過程 中分析中可以知道, handleBindApplication 函式中會呼叫 makeApplication
makeApplication會建立Application以及建立 ContextImpl
建立 ContextImpl
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this); 複製程式碼
這裡的this是 LoadedApk 物件,該物件是在 handleBinderApplication 中賦值
data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo); 複製程式碼
在該函式中,會根據 AppBindData(handleBinderApplication中的引數) 中的ApplicationInfo的mPackageName建立一個PackageInfo物件並儲存為ActivityThread類的全域性物件
顯然,一個應用程式中所有Activity或者Application或Servie,他們的mPackageName是一樣的,即為包名,因此ActivityThread只會有一個全域性的PackageInfo物件
在 newApplication的函式中會呼叫 Application 的 attach
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
Activity的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
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; } 複製程式碼
attach
建立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的Context建立
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