理解Context

是什麼

從應用場景的角度來講,他是一個場景,一個用戶與系統交互的過程.好比當你看短信時,場景包括短信的頁面,以及隱藏在後面的數據java

提到頁面,咱們應該可以聯想到 Activityapp

沒錯,Activity,Service都是一個Contextide

從JAVA語言角度來講,Context是一個抽象類,抽象類中包含了Application環境的一些函數,設計角度而言,Context僅提供某些功能, extends 纔是類的本質,即 Activity 的本質是一個 Context ,其所實現的其餘接口只是爲了擴充 Context 的功能而已,擴充後的類稱之爲 Activity 或 Service函數

有多少Context

  • Application一個Context
  • 多少個Activity就有多少個Context
  • 多少個Service就有多少個Context

Context個數=1 + Activity個數 + Service個數this

Application的Context建立

在博客 ActivityThread.main過程 中分析中能夠知道, handleBindApplication 函數中會調用 makeApplicationspa

makeApplication會建立Application以及建立 ContextImpl設計

建立 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

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

總結

不一樣Context子類中PackageInfo對象來源

類名 遠程數據類 本地數據類 賦值方式
Application ApplicationInfo AppBindData getPackageInfoNoCheck
Activity ActivityInfo ActivityClientRecord getPackageInfo
Service ServiceInfo CreateServiceData getPackageInfoNoCheck

參考書籍: Android內核剖析

相關文章
相關標籤/搜索