? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??? ? ? ? ? ? ? ? Context
?? Context熙含,翻譯是上下文環(huán)境各吨,在android應(yīng)用開發(fā)中的地位舉足輕重胁住,甚至源碼也有一句話:everything needs a context(看到過筹吐,但是忘了在哪里了)猛频。
從這個類圖中我們看到狮崩,Context是一個抽象類,一邊是Context的具體實現(xiàn)ContextImpl鹿寻,一邊則是組件的封裝類ContextWrapper睦柴,便于二者各司其職,我理解是接口和實現(xiàn)分開毡熏,這樣比較符合開閉原則吧坦敌。
? 既然要搞清楚Context是干嘛的,得先看Context的實例什么時候創(chuàng)建的招刹。這里有兩個我們經(jīng)常接觸的組件恬试,Activity和Service,以及用的較少的Application疯暑,它們的關(guān)系如下:
? ? 1.Application:保存應(yīng)用的全局信息的類训柴,它的實例在應(yīng)用創(chuàng)建的時候被創(chuàng)建,生命周期最長妇拯,應(yīng)用銷毀了才會被銷毀幻馁。
? ? 2.Activity:創(chuàng)建一個Activity便對應(yīng)一個Context的實例,生命周期隨著Activity的周期變化越锈。
? ? 3.Service:創(chuàng)建一個Service便對應(yīng)一個Context的實例仗嗦,生命周期隨著Service的周期變化。
下面逐一看看它們是什么時候?qū)嵗鼵ontext類的甘凭,我們需要知道稀拐,一個ContextWrapper類對應(yīng)一個ContextImpl類的實例,因為具體實現(xiàn)的地方還是在ContextImpl中丹弱,ContextWrapper中的mBase變量指向ContextImpl變量的實例德撬。
(1) Application的Context創(chuàng)建:
如圖:
? 跳過Process創(chuàng)建過程,在我們的應(yīng)用被zygote進(jìn)程孵化出來后躲胳,被反射調(diào)用main函數(shù)蜓洪,這里會創(chuàng)建ActivityThread類的實例,該類并不是一個線程類的子類坯苹,但是它的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)度菊霜,這里我們傳入這個服務(wù)端的句柄坚冀,讓AMS持有济赎,從而AMS可以通過這個句柄來操控應(yīng)用的行為鉴逞。我們向AMS請求,則是通過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對象保存到ProcessRecord中
? ? ? ? ?? if (app.instr != null) {
? ? ? ? ? ? ?? thread.bindApplication(processName, appInfo, providers,? //通知客戶端創(chuàng)建Application對象
? ? ? ? ? ? ? ? ? ? ?? 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的實現(xiàn)端中构捡,就是把跨進(jìn)程傳遞過來的各種數(shù)據(jù)再用一個AppBindData類保存下來,然后調(diào)用Handler對象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類對象
? ? ? ? ? ? ?? 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類對象
? ? ?? mInitialApplication = app;
? ? ?? }
}
? ? Instrumentation類是用于管理Acitivty的工具類统扳。這又有一個比較重要的對象出現(xiàn)喘帚,LoadedApk,它里面保存了類加載器ClassLoader咒钟,data.info的對象便是它吹由,makeApplication函數(shù)中的邏輯:
public Application makeApplication(boolean forceDefaultAppClass,
? ? ?? Instrumentation instrumentation) {
?? if (mApplication != null) {? //保證唯一性,不會重復(fù)創(chuàng)建Application對象朱嘴,所以我們可以認(rèn)為Application對象是單例的
? ? ?? return mApplication;
?? }
?? Application app = null;
?? String appClass = mApplicationInfo.className;
?? try {
? ? ?? java.lang.ClassLoader cl = getClassLoader();? //獲取類加載器實例
? ? ?? ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this); //創(chuàng)建ContextImpl實例
? ? ?? app = mActivityThread.mInstrumentation.newApplication( ? //實際創(chuàng)建Application對象的地方
? ? ? ? ? ? ?? 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)建時機(jī)倾鲫,就是在Application實例創(chuàng)建的時候:
?? 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對象賦值給創(chuàng)建的ContextImpl萍嬉,至此Application的創(chuàng)建就完成了乌昔,getApplicationContext() 返回的便是此處我們創(chuàng)建的Application類的對象。
? 這里為什么要去LoadedApk類中利用類加載器壤追,把對象創(chuàng)建出來呢磕道?因為我們的Application類是可以自己拓展的,創(chuàng)建的時候是不確定應(yīng)用自己是否復(fù)寫了Application對象行冰,利用類加載器就可以動態(tài)決定創(chuàng)建什么類的對象了溺蕉,我們只需要從PMS中獲取到application的具體類名即可,這個類名是寫在Mainfest文件中的资柔,后面Activity也是利用這種機(jī)制去創(chuàng)建對象焙贷。
(2)Actvity的啟動過程,網(wǎng)上非常多文章分析了贿堰,我也就不再重復(fù)羅列出來了赞咙,大概的過程就是startActivity()被調(diào)用,然后檢查目標(biāo)Acitivity的進(jìn)程是否創(chuàng)建杆煞,沒創(chuàng)建就先向Zygote進(jìn)程請求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對象實例
?? Activity activity = null;
?? try {
? ? ?? java.lang.ClassLoader cl = appContext.getClassLoader();
? ? ?? activity = mInstrumentation.newActivity( ? ? ? ? ? ?? //Activity對象創(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了,返回之前的對象
? ? ?? 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)用時機(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實例化過程趣效。同樣的瘦癌,這里也會創(chuàng)建ContextImpl對象,在Activity對象創(chuàng)建后跷敬,調(diào)用Attach()讯私,這個函數(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); ? //同樣的西傀,會調(diào)用此函數(shù)為ContextWrapper中的mBase對象賦值一個創(chuàng)建的ContextImpl對象
?? mWindow = new PhoneWindow(this, window, activityConfigCallback);? //創(chuàng)建PhoneWindow斤寇,這是對window操作的一系列操作的封裝
?? mWindow.setWindowControllerCallback(this);
?? mWindow.setCallback(this); ? ? ? ? ? ? ? ? ?? //設(shè)置callback是這個activity,有window相關(guān)的變化可以通知到這個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ù)中拥褂,也會為ContextWrapper中的mBase對象賦值一個ContextImpl對象娘锁,我們這里也能猜想到Service的創(chuàng)建估計也會有這個過程,而事實上Service的創(chuàng)建差不多也是這個過程肿仑,所以不再贅述了致盟。
? ? 我們可以知道Context例的實例化都是在我們在Application,Activity和Service創(chuàng)建的時候會實例化尤慰,而這些組件的父類都是ContextWrapper馏锡,所以在創(chuàng)建的時候還會先創(chuàng)建一個ContextImpl類對象,然后給自己的父類mBase變量賦值伟端,既然如此杯道,Context的引用對應(yīng)的就是Application,Activity和Service了责蝠,Context的用處就是提供了一組抽象的函數(shù)党巾,讓子類去相對應(yīng)的實現(xiàn),當(dāng)你持有一個Context引用的時候霜医,你可以通過這個引用去獲取相對應(yīng)組件的信息齿拂。比如持有一個Activity的Context引用,你可以在別的地方調(diào)用startActivity()去啟動一個新的activity肴敛。
總結(jié):
? 1.Context是抽象類署海,所以實例化要在子類中吗购,Application,Service砸狞,Activity是我們實例化的地方捻勉,一般應(yīng)用創(chuàng)建會實例化一個Application類,Service和Activity則是在startService和StartActivity被調(diào)用的時候會實例化刀森,它們都會創(chuàng)建一個ContextImpl類實例踱启,給自己的父類ContextWrapper的mBase變量賦值。
? 2.Context是組件中通用操作的一組集合研底,當(dāng)具體的子類實例化后埠偿,可以在別的地方通過保存一個Context引用去獲取信息和通用操作等,也就是說飘哨,我們可以通過這個引用去獲取到這個應(yīng)用中的重要信息以及這個應(yīng)用的通用操作胚想。