Android啟動(dòng)Activity源碼分析(五)

再遇Looper&構(gòu)造ActivityClientRecord

上一篇文章分析到:app.thread.scheduleLaunchActivity會(huì)跨進(jìn)程通知App進(jìn)程啟動(dòng)Activity。thread是android.app.ActivityThread.ApplicationThread類型的實(shí)例。
繼續(xù)分析android.app.ActivityThread.ApplicationThread#scheduleLaunchActivity:

        public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
                Bundle state, List<ResultInfo> pendingResults,
                List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
                String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
            ActivityClientRecord r = new ActivityClientRecord();

            r.token = token;
            r.ident = ident;
            r.intent = intent;
            r.activityInfo = info;
            r.compatInfo = compatInfo;
            r.state = state;

            r.pendingResults = pendingResults;
            r.pendingIntents = pendingNewIntents;

            r.startsNotResumed = notResumed;
            r.isForward = isForward;

            r.profileFile = profileName;
            r.profileFd = profileFd;
            r.autoStopProfiler = autoStopProfiler;

            //系統(tǒng)信息相關(guān)內(nèi)容,場(chǎng)景無(wú)關(guān)
            updatePendingConfiguration(curConfig);

            queueOrSendMessage(H.LAUNCH_ACTIVITY, r);
        }

參數(shù)挺多的,都是用于構(gòu)造ActivityClientRecord實(shí)例,前幾篇文章講過(guò)ActivityClientRecord是用來(lái)記錄App進(jìn)程側(cè)的Activity的,我們之前使用過(guò)MainActivity的ActivityClientRecord,而這次構(gòu)造的是屬于TargetActivity的ActivityClientRecord。

    private void queueOrSendMessage(int what, Object obj) {
        //是不是有點(diǎn)眼熟
        queueOrSendMessage(what, obj, 0, 0);
    }

是的,之前在pause掉MainActivity的時(shí)候就是調(diào)用的它,往looper里面拋信息的。這里思考一個(gè)問(wèn)題為什么要用looper去異步執(zhí)行?而不是直接順序同步執(zhí)行?
稍微思考一下即可得到答案:Binder是同步調(diào)用的,也就是說(shuō)執(zhí)行到這AMS還在等待App進(jìn)程執(zhí)行完成呢,同樣startActivity最初的調(diào)用處還在等待AMS執(zhí)行完成呢,如果不用looper異步執(zhí)行,那么系統(tǒng)進(jìn)程會(huì)一直被掛在那里,這哪能行呢,AMS還要處理其他的startActivity或者其他的跨進(jìn)程調(diào)用呢。
因此當(dāng)系統(tǒng)進(jìn)程通知App進(jìn)程執(zhí)行任務(wù)時(shí),都是通過(guò)looper的方式來(lái)執(zhí)行的。就好比一個(gè)母豬十個(gè)崽,奶就在那,已經(jīng)告訴你吃奶了,愛(ài)吃不吃,還有剩下九個(gè)崽要管呢。
android.app.ActivityThread.H#handleMessage:

        public void handleMessage(Message msg) {
            switch (msg.what) {
                case LAUNCH_ACTIVITY: {
                    ...
                    ActivityClientRecord r = (ActivityClientRecord)msg.obj;

                    r.packageInfo = getPackageInfoNoCheck(
                            r.activityInfo.applicationInfo, r.compatInfo);
                    handleLaunchActivity(r, null);
                    ...
                } break;
            ...
        }

onCreate、onStart、onResume的準(zhǔn)備工作

繼續(xù)分析android.app.ActivityThread#getPackageInfoNoCheck:


    public final LoadedApk getPackageInfoNoCheck(ApplicationInfo ai,
            CompatibilityInfo compatInfo) {
        return getPackageInfo(ai, compatInfo, null, false, true);
    }
    private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
            ClassLoader baseLoader, boolean securityViolation, boolean includeCode) {
        synchronized (mPackages) {
            WeakReference<LoadedApk> ref;
            //先從內(nèi)存緩存里取Apk信息
            if (includeCode) {
                ref = mPackages.get(aInfo.packageName);
            } else {
                ref = mResourcePackages.get(aInfo.packageName);
            }
            LoadedApk packageInfo = ref != null ? ref.get() : null;
            //取不到的話創(chuàng)建一個(gè),并且放在內(nèi)存緩存里,下次可以直接用
            if (packageInfo == null || (packageInfo.mResources != null
                    && !packageInfo.mResources.getAssets().isUpToDate())) {
                ...
                packageInfo =
                    new LoadedApk(this, aInfo, compatInfo, this, baseLoader,
                            securityViolation, includeCode &&
                            (aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0);
                if (includeCode) {
                    mPackages.put(aInfo.packageName,
                            new WeakReference<LoadedApk>(packageInfo));
                } else {
                    mResourcePackages.put(aInfo.packageName,
                            new WeakReference<LoadedApk>(packageInfo));
                }
            }
            return packageInfo;
        }
    }

具體如何執(zhí)行不再分析,該函數(shù)就是獲得了Apk的信息。賦值給了r.packageInfo。
android.app.ActivityThread#handleLaunchActivity:

    private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ...
        Activity a = performLaunchActivity(r, customIntent);

        if (a != null) {
            r.createdConfig = new Configuration(mConfiguration);
            Bundle oldState = r.state;
            handleResumeActivity(r.token, false, r.isForward);
            ...
        } else {
            ...
        }
    }

onCreate、onStart的調(diào)用

函數(shù)代碼比較長(zhǎng),實(shí)際上場(chǎng)景相關(guān)的只有兩行,分別是performLaunchActivity和handleResumeActivity的調(diào)用。
先分析android.app.ActivityThread#performLaunchActivity。
函數(shù)比較長(zhǎng)(難道google編碼規(guī)范,沒(méi)有限制函數(shù)行數(shù)嗎,100多行了),分兩段進(jìn)行分析,第一段:


    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ActivityInfo aInfo = r.activityInfo;
        //若沒(méi)有拿到Apk信息,再次嘗試取拿,不走這,之前已經(jīng)拿到了Apk信息,上文分析過(guò)
        if (r.packageInfo == null) {
            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                    Context.CONTEXT_INCLUDE_CODE);
        }

        ComponentName component = r.intent.getComponent();
        //當(dāng)前場(chǎng)景的組件名不會(huì)為null。若是null,還會(huì)嘗試向PMS查找
        if (component == null) {
            component = r.intent.resolveActivity(
                mInitialApplication.getPackageManager());
            r.intent.setComponent(component);
        }
        ...

        Activity activity = null;
        try {
            //拿到ClassLoader
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            //利用ClassLoader和組件名(TargetActivity類全稱),實(shí)例化TargetActivity
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            //不知道干啥用的,場(chǎng)景無(wú)關(guān)
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            //一些賦值
            r.intent.setExtrasClassLoader(cl);
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
            ...
        }
        //第一段結(jié)束
        ...
    }

第一段核心內(nèi)容:創(chuàng)建Activity實(shí)例。
android.app.Instrumentation#newActivity(java.lang.ClassLoader, java.lang.String, android.content.Intent):

    public Activity newActivity(ClassLoader cl, String className,
            Intent intent)
            throws InstantiationException, IllegalAccessException,
            ClassNotFoundException {
        return (Activity)cl.loadClass(className).newInstance();
    }

創(chuàng)建過(guò)程很簡(jiǎn)單。
繼續(xù)分析系第二段:

    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ...
        //第二段開(kāi)始
        try {
            //拿到App進(jìn)程對(duì)應(yīng)的Application對(duì)象
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);
            ...

            if (activity != null) {
                //設(shè)置Activity相關(guān)的Context內(nèi)容
                ContextImpl appContext = new ContextImpl();
                appContext.init(r.packageInfo, r.token, this);
                appContext.setOuterContext(activity);
                ...
                //把一些信息設(shè)置個(gè)Activity,其中Activity的”身份證”mToken就是在這里設(shè)置的
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config);
                ...
                activity.mCalled = false;
                //調(diào)用onCreate
                mInstrumentation.callActivityOnCreate(activity, r.state);
                if (!activity.mCalled) {
                    throw new SuperNotCalledException(
                        "Activity " + r.intent.getComponent().toShortString() +
                        " did not call through to super.onCreate()");
                }
                //把Activity記錄給ActivityClientRecord
                r.activity = activity;
                //還沒(méi)有resume,先設(shè)置成true
                r.stopped = true;
                //onCreate調(diào)用后,馬上調(diào)用onStart
                if (!r.activity.mFinished) {
                    activity.performStart();
                    r.stopped = false;
                }
                ...
                
            }
            //還沒(méi)有resume,先設(shè)置成true
            r.paused = true;
            
            //把ActivityClientRecord記錄下來(lái)。前面文章中使用過(guò)mActivities查找MainActivity的ActivityClientRecord
            mActivities.put(r.token, r);

        } 
        ...

        return activity;
    }

這函數(shù)主要干了一下幾件事:

  1. 創(chuàng)建Activity實(shí)例
  2. 給Activity設(shè)置好Context
  3. 設(shè)置attach一些Activity需要的信息
  4. 調(diào)用Activity的onCreate方法
  5. 調(diào)用Activity的onStart方法
  6. 把Activity實(shí)例記錄下來(lái),方便后續(xù)查找
    這里再簡(jiǎn)單分析下onCreate的調(diào)用android.app.Instrumentation#callActivityOnCreate:
    public void callActivityOnCreate(Activity activity, Bundle icicle) {
        ...
        activity.performCreate(icicle);
        ...
    }
    final void performCreate(Bundle icicle) {
        onCreate(icicle);
        ...
        //Fragment的onActivityCreated分發(fā)
        mFragments.dispatchActivityCreated();
    }

調(diào)用和onPause類似,也是用過(guò)Instrumentation進(jìn)行調(diào)用,也會(huì)驗(yàn)證是否調(diào)用了super方法。不再贅述。
在onCreate里會(huì)調(diào)用setContentView來(lái)設(shè)置布局。
android.app.Activity#setContentView(int):

    public void setContentView(int layoutResID) {
        getWindow().setContentView(layoutResID);
        initActionBar();
    }

getWindow()返回的是com.android.internal.policy.impl.PhoneWindow類型的。

    @Override
    public void setContentView(int layoutResID) {
        if (mContentParent == null) {
            // 構(gòu)造DecorView
            installDecor();
        } else {
            mContentParent.removeAllViews();
        }
        // 根據(jù)xml創(chuàng)建View樹(shù)
        mLayoutInflater.inflate(layoutResID, mContentParent);
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
    }

setContentView構(gòu)造DecorView和View樹(shù),這里不是本文重點(diǎn),不再分析。

onResume的調(diào)用

繼續(xù)回到handleLaunchActivity中,分析:
android.app.ActivityThread#handleResumeActivity:

    final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {
        ...
        // 執(zhí)行onResume
        ActivityClientRecord r = performResumeActivity(token, clearHide);

        if (r != null) {
            final Activity a = r.activity;

            if (localLOGV) Slog.v(
                TAG, "Resume " + r + " started activity: " +
                a.mStartedActivity + ", hideForNow: " + r.hideForNow
                + ", finished: " + a.mFinished);
    
            final int forwardBit = isForward ?
                    WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;

            // If the window hasn't yet been added to the window manager,
            // and this guy didn't finish itself or start another activity,
            // then go ahead and add the window.
            boolean willBeVisible = !a.mStartedActivity;
            if (!willBeVisible) {
                ...
            }
            //記錄Window、DecorView等。最后把View加進(jìn)Window(使用ViewRootImpl進(jìn)行add)
            if (r.window == null && !a.mFinished && willBeVisible) {
                r.window = r.activity.getWindow();
                View decor = r.window.getDecorView();
                //暫時(shí)設(shè)置成INVISIBLE
                decor.setVisibility(View.INVISIBLE);
                ViewManager wm = a.getWindowManager();
                WindowManager.LayoutParams l = r.window.getAttributes();
                a.mDecor = decor;
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
                if (a.mVisibleFromClient) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l);
                }
            } else if (!willBeVisible) {
                ...
            }
            ...
                    // 里面會(huì)把DecorView設(shè)置成VISIBLE
                    r.activity.makeVisible();
    }

代碼比較長(zhǎng),但場(chǎng)景有用的就兩步:

  1. 調(diào)用onResume函數(shù)
  2. 記錄Window、DecorView等到ActivityClientRecord里,并把View添加進(jìn)Window

下面我們繼續(xù)分析android.app.ActivityThread#performResumeActivity:

    public final ActivityClientRecord performResumeActivity(IBinder token,
            boolean clearHide) {
        //根據(jù)token拿ActivityClientRecord,老套路了
        ActivityClientRecord r = mActivities.get(token);
        ...
        //顯而易見(jiàn),走這兒
        if (r != null && !r.activity.mFinished) {
            //clearHide傳入的是true,設(shè)置了一些變量,一時(shí)半會(huì)兒用不到
            if (clearHide) {
                r.hideForNow = false;
                r.activity.mStartedActivity = false;
            }
            try {
                ...
                //里面用調(diào)用onResume
                r.activity.performResume();
                ...

                //這倆在調(diào)用onCreate的時(shí)候都設(shè)置成true了,現(xiàn)在已經(jīng)resume了,設(shè)置成false
                r.paused = false;
                r.stopped = false;
                r.state = null;
            } catch (Exception e) {
                ...
            }
        }
        return r;
    }

過(guò)程很簡(jiǎn)單,注釋里已經(jīng)能描述清楚了。主要是調(diào)用onResume和設(shè)置狀態(tài)值。
繼續(xù)看下android.app.Activity#performResume:

    final void performResume() {
        //里面會(huì)調(diào)用onRestart聲明和周期函數(shù)
        performRestart();
        ...
        mCalled = false;
        //依然是老套路,通過(guò)Instrumentation調(diào)用onResume,并且必須調(diào)用super方法
        mInstrumentation.callActivityOnResume(this);
        if (!mCalled) {
            throw new SuperNotCalledException(
                "Activity " + mComponent.toShortString() +
                " did not call through to super.onResume()");
        }

        mCalled = false;
        
        //Fragement分發(fā)resume
        mFragments.dispatchResume();
        ...
        if (!mCalled) {
            throw new SuperNotCalledException(
                "Activity " + mComponent.toShortString() +
                " did not call through to super.onPostResume()");
        }
    }

onResume和onPause、onCreate不同的是,它會(huì)嘗試調(diào)用一下onRestart。
android.app.Activity#performRestart:

    final void performRestart() {
        mFragments.noteStateNotSaved();

        //很顯然這里是false,不會(huì)走進(jìn)去。只有當(dāng)退出Activity的時(shí)候才是true,才會(huì)調(diào)用onRestart聲明周期函數(shù)
        if (mStopped) {
            ....
            performStart();
        }
    }

這里也印證了啟動(dòng)Activity的聲明周期函數(shù)不包括onRestart。
android.app.Instrumentation#callActivityOnResume:

    public void callActivityOnResume(Activity activity) {
        activity.mResumed = true;
        activity.onResume();
        ...
    }

這里就是onResume的調(diào)用了。

任務(wù)完成

我們知道周期函數(shù)是在looper里執(zhí)行的,跨進(jìn)程的調(diào)用實(shí)際上早已返回到了AMS中。當(dāng)Handler的LAUNCH_ACTIVITY消息發(fā)后,這時(shí)AMS的主要任務(wù)就已經(jīng)完成了。而App進(jìn)程側(cè)完成了LAUNCH_ACTIVITY消息里的內(nèi)容后,TargetActivity就算真正被啟動(dòng)了。

總結(jié)

App進(jìn)程側(cè)的任務(wù)執(zhí)行都通過(guò)Looper來(lái)執(zhí)行的,不能一直阻塞著系統(tǒng)進(jìn)程。

  1. App進(jìn)程側(cè)記錄了構(gòu)造ActivityClientRecord,并且通過(guò)android.app.Activity#mToken映射好,存下來(lái),以備以后使用。
  2. 調(diào)用了onCreate、onStart
  3. 調(diào)用onResume。調(diào)用前檢查了是否需要調(diào)用onRestart,發(fā)現(xiàn)不用調(diào)用。
?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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