Context是什么

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??? ? ? ? ? ? ? ? Context

?? Context,翻譯是上下文環(huán)境,在android應(yīng)用開發(fā)中的地位舉足輕重,甚至源碼也有一句話:everything needs a context(看到過,但是忘了在哪里了)。


Context類圖結(jié)構(gòu)

從這個(gè)類圖中我們看到,Context是一個(gè)抽象類,一邊是Context的具體實(shí)現(xiàn)ContextImpl,一邊則是組件的封裝類ContextWrapper,便于二者各司其職,我理解是接口和實(shí)現(xiàn)分開,這樣比較符合開閉原則吧。

? 既然要搞清楚Context是干嘛的,得先看Context的實(shí)例什么時(shí)候創(chuàng)建的。這里有兩個(gè)我們經(jīng)常接觸的組件,Activity和Service,以及用的較少的Application,它們的關(guān)系如下:

? ? 1.Application:保存應(yīng)用的全局信息的類,它的實(shí)例在應(yīng)用創(chuàng)建的時(shí)候被創(chuàng)建,生命周期最長(zhǎng),應(yīng)用銷毀了才會(huì)被銷毀。

? ? 2.Activity:創(chuàng)建一個(gè)Activity便對(duì)應(yīng)一個(gè)Context的實(shí)例,生命周期隨著Activity的周期變化。

? ? 3.Service:創(chuàng)建一個(gè)Service便對(duì)應(yīng)一個(gè)Context的實(shí)例,生命周期隨著Service的周期變化。

下面逐一看看它們是什么時(shí)候?qū)嵗鼵ontext類的,我們需要知道,一個(gè)ContextWrapper類對(duì)應(yīng)一個(gè)ContextImpl類的實(shí)例,因?yàn)榫唧w實(shí)現(xiàn)的地方還是在ContextImpl中,ContextWrapper中的mBase變量指向ContextImpl變量的實(shí)例。


(1) Application的Context創(chuàng)建:

如圖:


Application的創(chuàng)建過程

? 跳過Process創(chuàng)建過程,在我們的應(yīng)用被zygote進(jìn)程孵化出來后,被反射調(diào)用main函數(shù),這里會(huì)創(chuàng)建ActivityThread類的實(shí)例,該類并不是一個(gè)線程類的子類,但是它的main函數(shù)跑在新創(chuàng)建的進(jìn)程的主線程。 創(chuàng)建后,調(diào)用attach方法,與AMS綁定:

```java

private void attach(boolean system) {

? ? if (!system) {

? ? ? ? final IActivityManager mgr = ActivityManager.getService();

? ? ? ? try {

? ? ? ? ? ? mgr.attachApplication(mAppThread);? // final ApplicationThread mAppThread = new ApplicationThread();

? ? ? ? } catch (RemoteException ex) {

? ? ? ? ? ? throw ex.rethrowFromSystemServer();

? ? ? ? }

? ? }

}

```

這里傳入的mAppThread變量為ApplicationThread類,它為ActivityThread的內(nèi)部類,作用就是作為應(yīng)用端的binder服務(wù)端,負(fù)責(zé)接收AMS的調(diào)度,這里我們傳入這個(gè)服務(wù)端的句柄,讓AMS持有,從而AMS可以通過這個(gè)句柄來操控應(yīng)用的行為。我們向AMS請(qǐng)求,則是通過AMS的句柄。接下來就到了AMS的邏輯:

@Override

public final void attachApplication(IApplicationThread thread) {

?? synchronized (this) {

? ? ?? int callingPid = Binder.getCallingPid();

? ? ?? final long origId = Binder.clearCallingIdentity();

? ? ?? attachApplicationLocked(thread, callingPid);

? ? ?? Binder.restoreCallingIdentity(origId);

?? }

}

-----------------------------------------------------------------------

?? private final boolean attachApplicationLocked(IApplicationThread thread,

? ? ? ? ?? int pid) {

? ? ? ? ?? ProcessRecord app;? //app進(jìn)程的各種信息

? ? ? ? ?? app.makeActive(thread, mProcessStats);? //將IApplicationThread對(duì)象保存到ProcessRecord中

? ? ? ? ?? if (app.instr != null) {

? ? ? ? ? ? ?? thread.bindApplication(processName, appInfo, providers,? //通知客戶端創(chuàng)建Application對(duì)象

? ? ? ? ? ? ? ? ? ? ?? app.instr.mClass,

? ? ? ? ? ? ? ? ? ? ?? profilerInfo, app.instr.mArguments,

? ? ? ? ? ? ? ? ? ? ?? app.instr.mWatcher,

? ? ? ? ? ? ? ? ? ? ?? app.instr.mUiAutomationConnection, testMode,

? ? ? ? ? ? ? ? ? ? ?? mBinderTransactionTrackingEnabled, enableTrackAllocation,

? ? ? ? ? ? ? ? ? ? ?? isRestrictedBackupMode || !normalMode, app.persistent,

? ? ? ? ? ? ? ? ? ? ?? new Configuration(getGlobalConfiguration()), app.compat,

? ? ? ? ? ? ? ? ? ? ?? getCommonServicesLocked(app.isolated),

? ? ? ? ? ? ? ? ? ? ?? mCoreSettingsObserver.getCoreSettingsLocked(),

? ? ? ? ? ? ? ? ? ? ?? buildSerial);

? ? ? ? ?? } else {

? ? ? ? ? ? ?? thread.bindApplication(processName, appInfo, providers, null, profilerInfo,

? ? ? ? ? ? ? ? ? ? ?? null, null, null, testMode,

? ? ? ? ? ? ? ? ? ? ?? mBinderTransactionTrackingEnabled, enableTrackAllocation,

? ? ? ? ? ? ? ? ? ? ?? isRestrictedBackupMode || !normalMode, app.persistent,

? ? ? ? ? ? ? ? ? ? ?? new Configuration(getGlobalConfiguration()), app.compat,

? ? ? ? ? ? ? ? ? ? ?? getCommonServicesLocked(app.isolated),

? ? ? ? ? ? ? ? ? ? ?? mCoreSettingsObserver.getCoreSettingsLocked(),

? ? ? ? ? ? ? ? ? ? ?? buildSerial);

? ? ? ? ?? }

? ? ?? return true;

?? }

? ? 在ApplicationThread的實(shí)現(xiàn)端中,就是把跨進(jìn)程傳遞過來的各種數(shù)據(jù)再用一個(gè)AppBindData類保存下來,然后調(diào)用Handler對(duì)象H發(fā)送消息BIND_APPLICATION,最后在app線程中處理此邏輯,讓AMS線程可以不必同步阻塞。接下來就到了handleBindApplication:

private void handleBindApplication(AppBindData data) {

?? mBoundApplication = data;

?? final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);

?? updateLocaleListFromAppContext(appContext,

? ? ? ? ?? mResourcesManager.getConfiguration().getLocales());

?? if (ii != null) {

? ? ?? final ApplicationInfo instrApp = new ApplicationInfo();

? ? ?? ii.copyTo(instrApp);

? ? ?? instrApp.initForUser(UserHandle.myUserId());

? ? ?? final LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,

? ? ? ? ? ? ?? appContext.getClassLoader(), false, true, false);

? ? ?? final ContextImpl instrContext = ContextImpl.createAppContext(this, pi);

? ? ?? try {

? ? ? ? ?? final ClassLoader cl = instrContext.getClassLoader();

? ? ? ? ?? mInstrumentation = (Instrumentation) ? //創(chuàng)建Instrumentation類對(duì)象

? ? ? ? ? ? ?? cl.loadClass(data.instrumentationName.getClassName()).newInstance();

? ? ?? } catch (Exception e) {

? ? ? ? ?? throw new RuntimeException(

? ? ? ? ? ? ?? "Unable to instantiate instrumentation "

? ? ? ? ? ? ?? + data.instrumentationName + ": " + e.toString(), e);

? ? ?? }

? ? ?? final ComponentName component = new ComponentName(ii.packageName, ii.name);

? ? ?? mInstrumentation.init(this, instrContext, appContext, component,

? ? ? ? ? ? ?? data.instrumentationWatcher, data.instrumentationUiAutomationConnection);? //初始化Instrumentation

?? try {

? ? ?? // If the app is being launched for full backup or restore, bring it up in

? ? ?? // a restricted environment with the base application class.

? ? ?? Application app = data.info.makeApplication(data.restrictedBackupMode, null);? //創(chuàng)建Application類對(duì)象

? ? ?? mInitialApplication = app;

? ? ?? }

}

? ? Instrumentation類是用于管理Acitivty的工具類。這又有一個(gè)比較重要的對(duì)象出現(xiàn),LoadedApk,它里面保存了類加載器ClassLoader,data.info的對(duì)象便是它,makeApplication函數(shù)中的邏輯:

public Application makeApplication(boolean forceDefaultAppClass,

? ? ?? Instrumentation instrumentation) {

?? if (mApplication != null) {? //保證唯一性,不會(huì)重復(fù)創(chuàng)建Application對(duì)象,所以我們可以認(rèn)為Application對(duì)象是單例的

? ? ?? return mApplication;

?? }

?? Application app = null;

?? String appClass = mApplicationInfo.className;

?? try {

? ? ?? java.lang.ClassLoader cl = getClassLoader();? //獲取類加載器實(shí)例

? ? ?? ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this); //創(chuàng)建ContextImpl實(shí)例

? ? ?? app = mActivityThread.mInstrumentation.newApplication( ? //實(shí)際創(chuàng)建Application對(duì)象的地方

? ? ? ? ? ? ?? cl, appClass, appContext); ?

? ? ?? appContext.setOuterContext(app);

?? } catch (Exception e) {

? ? ?? if (!mActivityThread.mInstrumentation.onException(app, e)) {

? ? ? ? ?? Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

? ? ? ? ?? throw new RuntimeException(

? ? ? ? ? ? ?? "Unable to instantiate application " + appClass

? ? ? ? ? ? ?? + ": " + e.toString(), e);

? ? ?? }

?? }

?? mActivityThread.mAllApplications.add(app);

?? mApplication = app;

?? if (instrumentation != null) {

? ? ?? try {

? ? ? ? ?? instrumentation.callApplicationOnCreate(app); ? //Application的onCreate()被調(diào)用

? ? ?? } catch (Exception e) {

? ? ? ? ?? if (!instrumentation.onException(app, e)) {

? ? ? ? ? ? ?? Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

? ? ? ? ? ? ?? throw new RuntimeException(

? ? ? ? ? ? ? ? ?? "Unable to create application " + app.getClass().getName()

? ? ? ? ? ? ? ? ?? + ": " + e.toString(), e);

? ? ? ? ?? }

? ? ?? }

?? }

?? return app;

}

? 這里我們看到了ContextImpl的創(chuàng)建時(shí)機(jī),就是在Application實(shí)例創(chuàng)建的時(shí)候:

?? 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的創(chuàng)建,并且調(diào)用attach方法把Application的mBase對(duì)象賦值給創(chuàng)建的ContextImpl,至此Application的創(chuàng)建就完成了,getApplicationContext() 返回的便是此處我們創(chuàng)建的Application類的對(duì)象。


? 這里為什么要去LoadedApk類中利用類加載器,把對(duì)象創(chuàng)建出來呢?因?yàn)槲覀兊腁pplication類是可以自己拓展的,創(chuàng)建的時(shí)候是不確定應(yīng)用自己是否復(fù)寫了Application對(duì)象,利用類加載器就可以動(dòng)態(tài)決定創(chuàng)建什么類的對(duì)象了,我們只需要從PMS中獲取到application的具體類名即可,這個(gè)類名是寫在Mainfest文件中的,后面Activity也是利用這種機(jī)制去創(chuàng)建對(duì)象。

(2)Actvity的啟動(dòng)過程,網(wǎng)上非常多文章分析了,我也就不再重復(fù)羅列出來了,大概的過程就是startActivity()被調(diào)用,然后檢查目標(biāo)Acitivity的進(jìn)程是否創(chuàng)建,沒創(chuàng)建就先向Zygote進(jìn)程請(qǐng)求fork應(yīng)用進(jìn)程,然后一系列初始化過程后,最后在AMS模塊中的ActivityStackSupervisor中realStartActivityLocked()調(diào)用IApplicationThread代理類,調(diào)用到scheduleLaunchActivity(),然后在應(yīng)用的線程開始執(zhí)行handleLaunchActivity(),最主要的邏輯在performLaunchActivity:

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {

?? ActivityInfo aInfo = r.activityInfo;

?? if (r.packageInfo == null) {

? ? ?? r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,

? ? ? ? ? ? ?? Context.CONTEXT_INCLUDE_CODE);

?? }

?? ContextImpl appContext = createBaseContextForActivity(r);? //創(chuàng)建ContextImpl對(duì)象實(shí)例

?? Activity activity = null;

?? try {

? ? ?? java.lang.ClassLoader cl = appContext.getClassLoader();

? ? ?? activity = mInstrumentation.newActivity( ? ? ? ? ? ?? //Activity對(duì)象創(chuàng)建

? ? ? ? ? ? ?? cl, component.getClassName(), r.intent);

? ? ?? StrictMode.incrementExpectedActivityCount(activity.getClass());

? ? ?? r.intent.setExtrasClassLoader(cl);

? ? ?? r.intent.prepareToEnterProcess();

? ? ?? if (r.state != null) {

? ? ? ? ?? r.state.setClassLoader(cl);

? ? ?? }

?? } catch (Exception e) {

? ? ?? if (!mInstrumentation.onException(activity, e)) {

? ? ? ? ?? throw new RuntimeException(

? ? ? ? ? ? ?? "Unable to instantiate activity " + component

? ? ? ? ? ? ?? + ": " + e.toString(), e);

? ? ?? }

?? }

?? try {

? ? ?? Application app = r.packageInfo.makeApplication(false, mInstrumentation); //應(yīng)用已經(jīng)創(chuàng)建過Application了,返回之前的對(duì)象

? ? ?? if (activity != null) {

? ? ? ? ?? appContext.setOuterContext(activity);

? ? ? ? ?? activity.attach(appContext, this, getInstrumentation(), r.token, ? //初始化activity

? ? ? ? ? ? ? ? ?? r.ident, app, r.intent, r.activityInfo, title, r.parent,

? ? ? ? ? ? ? ? ?? r.embeddedID, r.lastNonConfigurationInstances, config,

? ? ? ? ? ? ? ? ?? r.referrer, r.voiceInteractor, window, r.configCallback);

? ? ? ? ?? if (r.isPersistable()) {

? ? ? ? ? ? ?? mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);? //oncreate調(diào)用時(shí)機(jī)

? ? ? ? ?? } else {

? ? ? ? ? ? ?? mInstrumentation.callActivityOnCreate(activity, r.state);

? ? ? ? ?? }

? ? ? ? ?? if (!r.activity.mFinished) {

? ? ? ? ? ? ?? if (r.isPersistable()) {

? ? ? ? ? ? ? ? ?? if (r.state != null || r.persistentState != null) {

? ? ? ? ? ? ? ? ? ? ?? mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state, //如果之前保存了數(shù)據(jù),可以在此恢復(fù)

? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? r.persistentState);

? ? ? ? ? ? ? ? ?? }

? ? ? ? ? ? ?? } else if (r.state != null) {

? ? ? ? ? ? ? ? ?? mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);

? ? ? ? ? ? ?? }

? ? ? ? ?? }

? ? ?? }

?? return activity;

}

? 至于Activity的生命周期后面怎么走的,這里不在乎,我們只看Context實(shí)例化過程。同樣的,這里也會(huì)創(chuàng)建ContextImpl對(duì)象,在Activity對(duì)象創(chuàng)建后,調(diào)用Attach(),這個(gè)函數(shù)挺重要的,我們看看都干了什么:

final void attach(Context context, ActivityThread aThread,

? ? ?? Instrumentation instr, IBinder token, int ident,

? ? ?? Application application, Intent intent, ActivityInfo info,

? ? ?? CharSequence title, Activity parent, String id,

? ? ?? NonConfigurationInstances lastNonConfigurationInstances,

? ? ?? Configuration config, String referrer, IVoiceInteractor voiceInteractor,

? ? ?? Window window, ActivityConfigCallback activityConfigCallback) {

?? attachBaseContext(context); ? //同樣的,會(huì)調(diào)用此函數(shù)為ContextWrapper中的mBase對(duì)象賦值一個(gè)創(chuàng)建的ContextImpl對(duì)象

?? mWindow = new PhoneWindow(this, window, activityConfigCallback);? //創(chuàng)建PhoneWindow,這是對(duì)window操作的一系列操作的封裝

?? mWindow.setWindowControllerCallback(this);

?? mWindow.setCallback(this); ? ? ? ? ? ? ? ? ?? //設(shè)置callback是這個(gè)activity,有window相關(guān)的變化可以通知到這個(gè)activity

?? mWindow.setOnWindowDismissedCallback(this);

?? mWindow.getLayoutInflater().setPrivateFactory(this);

?? if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {

? ? ?? mWindow.setSoftInputMode(info.softInputMode);

?? }

?? mUiThread = Thread.currentThread();

?? mMainThread = aThread;

?? mInstrumentation = instr;

?? mToken = token;

?? mIdent = ident;

?? mApplication = application;

?? mIntent = intent;

?? mReferrer = referrer;

?? mComponent = intent.getComponent();

?? mActivityInfo = info;

?? mTitle = title;

?? mParent = parent;

?? mEmbeddedID = id;


?? mWindow.setWindowManager( ? ? ? ? ? ?

? ? ? ? ?? (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),

? ? ? ? ?? mToken, mComponent.flattenToString(),

? ? ? ? ?? (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);

?? if (mParent != null) {

? ? ?? mWindow.setContainer(mParent.getWindow());

?? }

?? mWindowManager = mWindow.getWindowManager();

?? mCurrentConfig = config;

?? mWindow.setColorMode(info.colorMode);

}

? 在attach函數(shù)中,也會(huì)為ContextWrapper中的mBase對(duì)象賦值一個(gè)ContextImpl對(duì)象,我們這里也能猜想到Service的創(chuàng)建估計(jì)也會(huì)有這個(gè)過程,而事實(shí)上Service的創(chuàng)建差不多也是這個(gè)過程,所以不再贅述了。


? ? 我們可以知道Context例的實(shí)例化都是在我們?cè)贏pplication,Activity和Service創(chuàng)建的時(shí)候會(huì)實(shí)例化,而這些組件的父類都是ContextWrapper,所以在創(chuàng)建的時(shí)候還會(huì)先創(chuàng)建一個(gè)ContextImpl類對(duì)象,然后給自己的父類mBase變量賦值,既然如此,Context的引用對(duì)應(yīng)的就是Application,Activity和Service了,Context的用處就是提供了一組抽象的函數(shù),讓子類去相對(duì)應(yīng)的實(shí)現(xiàn),當(dāng)你持有一個(gè)Context引用的時(shí)候,你可以通過這個(gè)引用去獲取相對(duì)應(yīng)組件的信息。比如持有一個(gè)Activity的Context引用,你可以在別的地方調(diào)用startActivity()去啟動(dòng)一個(gè)新的activity。

總結(jié):

? 1.Context是抽象類,所以實(shí)例化要在子類中,Application,Service,Activity是我們實(shí)例化的地方,一般應(yīng)用創(chuàng)建會(huì)實(shí)例化一個(gè)Application類,Service和Activity則是在startService和StartActivity被調(diào)用的時(shí)候會(huì)實(shí)例化,它們都會(huì)創(chuàng)建一個(gè)ContextImpl類實(shí)例,給自己的父類ContextWrapper的mBase變量賦值。

? 2.Context是組件中通用操作的一組集合,當(dāng)具體的子類實(shí)例化后,可以在別的地方通過保存一個(gè)Context引用去獲取信息和通用操作等,也就是說,我們可以通過這個(gè)引用去獲取到這個(gè)應(yīng)用中的重要信息以及這個(gè)應(yīng)用的通用操作。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容