Android深刻理解Context(二)Activity和Service的Context建立過程

相關文章
Android深刻理解四大組件系列
Android深刻理解Context系列html

前言

上一篇文章咱們學習了Context關聯類和Application Context的建立過程,這一篇咱們接着來學習Activity和Service的Context建立過程。須要注意的是,本篇的知識點會和深刻理解四大組件系列的部分文章的知識點相重合。
java

1.Activity的Context建立過程

當咱們在Activity中調用startActivity方法時,其實調用的是Context的startActivity方法,若是想要在Activity中使用Context提供的方法,務必要先建立Context。Activity的Context會在Activity的啓動過程當中被建立,在Android深刻四大組件(一)應用程序啓動過程(後篇)的第二小節中,講到了ActivityThread啓動Activity的過程,咱們就從這裏開始分析。
ActivityThread是應用程序進程的核心類,它的內部類ApplicationThread會調用scheduleLaunchActivity方法來啓動Activity,scheduleLaunchActivity方法以下所示。android

frameworks/base/core/java/android/app/ActivityThread.java微信

@Override
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident, ActivityInfo info, Configuration curConfig, Configuration overrideConfig, CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state, PersistableBundle persistentState, List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents, boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
        updateProcessState(procState, false);
        ActivityClientRecord r = new ActivityClientRecord();
        r.token = token;
        ...
        sendMessage(H.LAUNCH_ACTIVITY, r);
}複製代碼

scheduleLaunchActivity方法會將啓動Activity的參數封裝成ActivityClientRecord ,sendMessage方法向H類發送類型爲LAUNCH_ACTIVITY的消息,並將ActivityClientRecord 傳遞過去。sendMessage方法的目的是將啓動Activity的邏輯放在主線程中的消息隊列中,這樣啓動Activity的邏輯就會在主線程中執行。
H類的handleMessage方法中會對LAUNCH_ACTIVITY類型的消息進行處理,其中調用了handleLaunchActivity方法,而handleLaunchActivity方法中又調用performLaunchActivity方法,這一過程在Android深刻理解Context(一)Context關聯類和Application Context建立過程已經講過了,咱們來查看performLaunchActivity方法。
frameworks/base/core/java/android/app/ActivityThread.javaapp

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ...
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);//1
             ...
            }
        } catch (Exception e) {
           ...
        }

        try {
          ...
            if (activity != null) {
                Context appContext = createBaseContextForActivity(r, activity);//2
                ...
                /** *3 */
                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); 
                ...
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);//4
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
               ...
        }

        return activity;
    }複製代碼

performLaunchActivity方法中有不少重要的邏輯,這裏只保留了Activity的Context相關的邏輯。在註釋1處用來建立Activity的實例。註釋2處經過createBaseContextForActivity方法用來建立Activity的ContextImpl,並將ContextImpl傳入註釋3處的activity的attach方法中。在註釋4處Instrumentation的callActivityOnCreate方法中會調用Activity的onCreate方法。
咱們先來查看註釋2出的createBaseContextForActivity方法:
frameworks/base/core/java/android/app/ActivityThread.javaide

private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
        ...
        ContextImpl appContext = ContextImpl.createActivityContext(
                this, r.packageInfo, r.token, displayId, r.overrideConfig);//1
        appContext.setOuterContext(activity);//2
        Context baseContext = appContext;
        ...
        return baseContext;
    }複製代碼

在註釋1處調用ContextImpl的createActivityContext方法來建立ContextImpl,註釋2處調用了ContextImpl的setOuterContext方法,將此前建立的Activity 實例賦值給ContextImpl的成員變量mOuterContext,這樣ContextImpl也能夠訪問Activity的變量和方法。
咱們再回到ActivityThread的performLaunchActivity方法,查看註釋3處的Activity的attach方法,以下所示。
frameworks/base/core/java/android/app/Activity.java學習

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) {
        attachBaseContext(context);//1
        mFragments.attachHost(null /*parent*/);
        mWindow = new PhoneWindow(this, window);//2
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);//3
        mWindow.setOnWindowDismissedCallback(this);
        ...
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);//4
        if (mParent != null) {
            mWindow.setContainer(mParent.getWindow());
        }
        mWindowManager = mWindow.getWindowManager();//5
        mCurrentConfig = config;
    }複製代碼

在註釋2處建立PhoneWindow,它表明應用程序窗口。PhoneWindow在運行中會間接觸發不少事件,好比點擊事件、菜單彈出、屏幕焦點變化等事件,這些事件須要轉發給與PhoneWindow關聯的Actvity,轉發操做經過Window.Callback接口實現,Actvity實現了這個接口,在註釋3處將當前Activity經過Window的setCallback方法傳遞給PhoneWindow。
註釋4處給PhoneWindow設置WindowManager,並在註釋5處獲取WindowManager並賦值給Activity的成員變量mWindowManager ,這樣在Activity中就能夠經過getWindowManager方法來獲取WindowManager。
在註釋1處調用了ContextThemeWrapper的attachBaseContext方法,以下所示。ui

frameworks/base/core/java/android/view/ContextThemeWrapper.javathis

@Override
protected void attachBaseContext(Context newBase) {
    super.attachBaseContext(newBase);
}複製代碼

attachBaseContext方法接着調用ContextThemeWrapper的父類ContextWrapper的attachBaseContext方法:spa

frameworks/base/core/java/android/content/ContextWrapper.java

protected void attachBaseContext(Context base) {
    if (mBase != null) {
        throw new IllegalStateException("Base context already set");
    }
    mBase = base;//1
}複製代碼

註釋1處的base指的是一路傳遞過來的Activity的ContextImpl,將它賦值給ContextWrapper的成員變量mBase。這樣ContextWrapper的功能就能夠交由ContextImpl處理,舉個例子:
frameworks/base/core/java/android/content/ContextWrapper.java

@Override
public Resources.Theme getTheme() {
    return mBase.getTheme();
}複製代碼

當咱們調用ContextWrapper的getTheme方法,其實就是調用的ContextImpl的getTheme方法。
Activity的Context建立過程就講到這裏。 總結一下,在啓動Activity的過程當中建立ContextImpl,並賦值給ContextWrapper的成員變量mBase中。Activity繼承自ContextWrapper的子類ContextThemeWrapper,這樣在Activity中就可使用ContextImpl了。
下面給出ActivityThread到ContextWrapper的調用時序圖。

2.Service的Context建立過程

Service的Context建立過程與Activity的Context建立過程相似,也是在Service的啓動過程當中被建立。在Android深刻四大組件(二)Service的啓動過程 這篇文章的第二節中講到了ActivityThread啓動Service的過程,咱們從這裏開始分析。
ActivityThread的內部類ApplicationThread會調用scheduleCreateService方法來啓動Service,以下所示。
frameworks/base/core/java/android/app/ActivityThread.java

public final void scheduleCreateService(IBinder token, ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
     ...
     sendMessage(H.CREATE_SERVICE, s);
 }複製代碼

sendMessage方法向H類發送CREATE_SERVICE類型的消息,H類的handleMessage方法中會對CREATE_SERVICE類型的消息進行處理,其中調用了handleCreateService方法:
frameworks/base/core/java/android/app/ActivityThread.java

private void handleCreateService(CreateServiceData data) {
      ...
        try {
            if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);//1
            context.setOuterContext(service);
            Application app = packageInfo.makeApplication(false, mInstrumentation);
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManagerNative.getDefault());//2
            service.onCreate();
          ...
        } catch (Exception e) {
          ... 
        }
    }複製代碼

在註釋1處建立了ContextImpl ,並將該ContextImpl傳入註釋2處service的attach方法中:
frameworks/base/core/java/android/app/Service.java

public final void attach( Context context, ActivityThread thread, String className, IBinder token, Application application, Object activityManager) {
        attachBaseContext(context);//1
        mThread = thread;           // NOTE: unused - remove?
        mClassName = className;
        mToken = token;
        mApplication = application;
        mActivityManager = (IActivityManager)activityManager;
        mStartCompatibility = getApplicationInfo().targetSdkVersion
                < Build.VERSION_CODES.ECLAIR;
    }複製代碼

註釋1處調用了ContextWrapper的attachBaseContext方法。
frameworks/base/core/java/android/content/ContextWrapper.java

protected void attachBaseContext(Context base) {
    if (mBase != null) {
        throw new IllegalStateException("Base context already set");
    }
    mBase = base;
}複製代碼

attachBaseContext方法在前文已經講過,這裏再也不贅述。
Service的Context建立過程就講解到這裏,因爲它和Activity的Context建立過程相似,所以,能夠參考前文給出的ActivityThread到ContextWrapper的調用時序圖。


歡迎關注個人微信公衆號,第一時間得到博客更新提醒,以及更多成體系的Android相關原創技術乾貨。
掃一掃下方二維碼或者長按識別二維碼,便可關注。

相關文章
相關標籤/搜索