Activity的啟動原理

前言

? 我還記得上個學(xué)期意外看到一篇文章,是凱子哥的一篇博客模叙,講的是app第一個activity啟動的底層過程(java)薄坏,我當時幾乎沒接觸過這塊的源碼侵浸,好像看了一半就放棄。還有一次刷知乎础嫡,看到一個人回答為什么ActivityThread里面Loop不會造成ANR杭跪,但是也是一臉萌比。這個學(xué)期開始刷藝術(shù)探索驰吓,已經(jīng)看完了第十章涧尿,每一章都對著源碼自己又看了一遍,再加上之前對Binder,IPC的淺顯的研究檬贰。今天重新再來看這篇文章[【凱子哥帶你學(xué)Framework】Activity啟動過程全解析]姑廉,發(fā)現(xiàn)基本上是看小說一樣的輕松看完了。翁涤。這是一種進步G叛浴!感覺挺好的葵礼。感謝大神的知識分享号阿,下面我用自己的方式來總結(jié)一下Activity啟動的過程,但是我跟凱子哥不同鸳粉,他講的那個其實就多了一點Launcher和applicaiton創(chuàng)建的知識扔涧。

? 說一點自己的學(xué)習(xí)感受。首先:

  • 源碼海洋里面不要太追求了解每一個細節(jié)届谈,不然分分鐘迷失自我枯夜。
  • 有些知識是需要有其他知識儲備才能理解的。所以看不懂的時候放一放艰山,過一段時間再來看湖雹。比如binder設(shè)計原理那塊我就留了一半。曙搬。因為后半部分有點看不太懂了摔吏,涉及到了C草。
  • 看書上的源碼遠遠不夠纵装,一定一定要自己去獨立的看一遍征讲,自己去把整個流程過一遍。
  • 畫草圖搂擦,流程圖稳诚。因為過程異常的復(fù)雜,在不同的類里面調(diào)來調(diào)用瀑踢,又臭又長的調(diào)用鏈扳还。
  • 永遠不要放棄才避,靜下心來研究,一切都不是問題氨距。

知識儲備

  1. Binder, IPC機制桑逝。可以看看我之前的兩篇文章Android-IPC系列(一)Android-IPC系列(二) 俏让。還有幾篇我覺得寫的非常好的文章Android Binder設(shè)計與實現(xiàn) - 設(shè)計篇 Android進程間通信(IPC)機制Binder簡要介紹和學(xué)習(xí)計劃 楞遏。(這兩篇講的都比較深)看到藝術(shù)探索后面我終于知道為什么binder要在第二章就講解了。因為Binder在后面幾乎是無處不在首昔!

  2. ActivityManagerService寡喝。本質(zhì)就是一個Binder,并且實體在服務(wù)端勒奇。AMS在遠端操作著activity的生命周期预鬓。這個進程由SystemServer進程fork出來。

  3. ActivityThread赊颠。大家都知道ActivityThread就是應(yīng)用的UI線程格二,main方法就是整個應(yīng)用的入口。ActivityThread本質(zhì)并不是一個線程竣蹦,他只是依附著主線程存在顶猜。ActivityThread通過和AMS進行IPC通信來共同管理Activity的生命周期。在后面我準備寫一篇關(guān)于Handle的續(xù)篇痘括,里面還會提到他长窄,因為主線程里面的Looper就是在這里init的。

  4. ApplicationThread.远寸。它是ActivityThread的內(nèi)部類抄淑,本質(zhì)上ActivityThread是通過它來進行和AMS的IPC通信的。它的本質(zhì)也是一個Binder驰后!只不過這次他的實體放在客戶端,AMS通過他的代理類ApplicationThreadProxy來和ApplicationThread通信矗愧。

  5. Instrumentation.灶芝。這個類我在看完第一遍書的時候感覺操作調(diào)用鏈里面的最外層。因為最后一步Activity實例對象的生成和onCreat()方法的調(diào)用最終是來自這個類的唉韭。其實這個類是ActivityThread想要進行的操作的具體操作類夜涕。這個類是全局的,并且每個acitivity里面都擁有一個它的引用属愤。

  6. ActivityStack(AMS中)女器。很好懂,一個activity棧住诸。但是這個ActivityStack是有兩種類型的驾胆,一種叫系統(tǒng)ActivityStack(HomeTask),這一類的ActivityStack包含著Launcher(或者有其他我不知道的)涣澡,還有一種是普通應(yīng)用的ActivityStack(安卓中Task這個概念的具體實現(xiàn)形式),其實就是一個Task(任務(wù)棧)丧诺。這個類是由AMS來管理入桂,AMS通過這個數(shù)據(jù)結(jié)構(gòu)來得知activity的狀態(tài)。

  7. ActivityStackSuperisor(AMS中)驳阎。加了一個單詞抗愁,就是activity棧的管理者。這個類的作用就是管理棧呵晚,并且通過ActivityStack來獲得要啟動的activity的信息蜘腌。

  8. ActivityRecord。這個就是上面說的服務(wù)端的actiivty信息的載體類饵隙。并且也是服務(wù)端的類~這個類相當?shù)闹匾橹椋允贾两K都貫穿在調(diào)用鏈里面,在安卓ActivityStack里面存儲的并不是activity實例癞季,其實就是這個ActivityRecord的實例劫瞳。

  9. ActivityClientRecord。這個和上面區(qū)別就是這個類是客戶端activity信息的載體類绷柒。

  10. TaskRecord志于。同樣,這個類就是ActivityTask的信息記錄類而已废睦。

    ?好了伺绽,我覺得需要好好了解的幾個最核心的類就是這幾個了,大家若不清楚嗜湃,可以自己去源碼里面看奈应,如果我有說錯的也請原諒。购披。杖挣。其實還有很多概念我在binder那篇文章里面講的不少了!這里算是又一次的補充吧刚陡。


Activity啟動的流程

? 源碼之旅開始惩妇。科科.

1.Activity.startActivity(Intent intent)這個我們天天都在寫筐乳,好歌殃,去看源碼!

@Override
    public void startActivity(Intent intent, @Nullable Bundle options) {
        if (options != null) {
            startActivityForResult(intent, -1, options);
        } else {
            // Note we want to go through this call for compatibility with
            // applications that may have overridden the method.
            startActivityForResult(intent, -1);
        }
    }

嗯蝙云,繼續(xù)看startActivityForResult()氓皱;

public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
        if (mParent == null) {
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
            if (ar != null) {
                mMainThread.sendActivityResult(
                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                    ar.getResultData());
            }
            ...省略代碼
    }

直接調(diào)用了Instrumentation去調(diào)用execStartActivity()方法。后面的調(diào)用先不管,直接去看execStartActivity()方法波材。需要注意的是mMainThread.getApplicationThread()就是通過ActivityThread去獲得了一個ApplicaitonThread實例

public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
        IApplicationThread whoThread = (IApplicationThread) contextThread;
        ...省略代碼
        try {
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess();
          //通過AMS啟動了
            int result = ActivityManagerNative.getDefault()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);
          //用來檢測這個activity啟動的結(jié)果股淡,具體可以去查看源碼
            checkStartActivityResult(result, intent);
        } catch (RemoteException e) {
        }
        return null;
    }

看到這里發(fā)現(xiàn)它又用了個什么玩意調(diào)用了startActivity()方法,這是什么呢各聘?這里的ActivityManagerNative.getDefault()就是我們期待了很久的ActivityManagerService的代理類揣非!如果你很清楚Binder的實現(xiàn),這個應(yīng)該難不倒你吧躲因!AMS和代理類本質(zhì)上都是IActivityManager的實現(xiàn)類早敬。(IAcitivtyManager,其實就是一個AIDL接口,不信自己去看源碼)大脉。我給你看看getDefault()方法的實現(xiàn):

private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
        protected IActivityManager create() {
            IBinder b = ServiceManager.getService("activity");
            if (false) {
                Log.v("ActivityManager", "default service binder = " + b);
            }
            IActivityManager am = asInterface(b);
            if (false) {
                Log.v("ActivityManager", "default service = " + am);
            }
            return am;
        }
    };

就是這么簡單搞监!如果看到這里你看不懂了,建議你再回去看看Binder镰矿。接下來我們就可以繼續(xù)看AMS中startActivity()方法的實現(xiàn)了:注意琐驴,從這里開始,調(diào)用鏈會變得很復(fù)雜

@Override
    public final int startActivity(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options) {
      //調(diào)用了startActivityAsUser,caller是我們的ApplicaitonThread
        return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
            resultWho, requestCode, startFlags, profilerInfo, options,
            UserHandle.getCallingUserId());
    }

繼續(xù)看這個startActivityAsUser()方法:

@Override
    public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {
        enforceNotIsolatedCaller("startActivity");
        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
                false, ALLOW_FULL_ONLY, "startActivity", null);
        // TODO: Switch to user app stacks here.轉(zhuǎn)換app里面的activity棧,caller是我們的ApplicaitonThread
        return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                profilerInfo, null, null, options, userId, null, null);
    }

? 發(fā)現(xiàn)調(diào)用了之前提到的ActivityStackSupervisor的startActivityMayWait()方法秤标。這里的目的就是想去通過棧的管理者來通過傳進來的數(shù)據(jù)去改變棧绝淡,并且拿到被啟動activity的ActivityRecord實例。

? 在startActivityMayWait()里面苍姜,主要做了ActivityStack牢酵, ActivityInfo, LaunchMode等等各種信息的初始化工作,然后就又調(diào)用了startActivityLocked()方法衙猪, 這個方法里面又做了一系列的變量初始化馍乙,初始啟動的錯誤判斷, uid檢查之后,又調(diào)用了startActivityUncheckedLocked()方法垫释。這個方法里面根據(jù)前面一系列的工作丝格,確定了最終的LanuchMode,這個LaunchMode會在后面的函數(shù)被拿來進行判斷,構(gòu)建了一個新的intent棵譬,ActivityInfo,ActivityTask显蝌。反正過程都TM又臭又長,細看下去一天就耗完了订咸。接下來我們可以看到最終調(diào)用targetStack.resumeTopActivityLocked()方法琅束。這個targetStack就是新的activity所要放入的Task的位置。也就是說算谈,現(xiàn)在又要轉(zhuǎn)到ActivityTask中去看源碼了,科科料滥!

? 注意的是然眼,LaunchMode和ActivityStack的選擇是個很復(fù)雜的過程。我推薦一篇文章以及安卓的官方文檔鏈接葵腹。官方文檔,頓文的博客


? 需要非常注意的是高每,這個函數(shù)執(zhí)行的時候屿岂,被啟動的activity里面被添加到棧里面去了,top鲸匿,next就是指代這個要被啟動的activity爷怀。pre,current就是指代當前resumed的activity。你別弄混了带欢,雖然這個問題我TM看了一整天的源碼运授。注意,被啟動的activity雖然還沒有被實例乔煞,但是它的ActivityRecord實例已經(jīng)被構(gòu)建出來了吁朦,并且已經(jīng)被添加到stack里面去了。具體的調(diào)用過程是:

? Supervisor.setActivityUnchekedLocked->resumeTopActivityLocked(這里是ActivityStackSuperbisor里面的方法)->ActivityStack.startActivityLocked在這里將activity添加到stack里面渡贾。并且在之后才會調(diào)用ActivityStack的resumeTopActivityLocked方法

/**
     * Ensure that the top activity in the stack is resumed.
     *
     * @param prev The previously resumed activity, for when in the process
     * of pausing; can be null to call from elsewhere.
     *
     * @return Returns true if something is being resumed, or false if
     * nothing happened.
     */
final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
        if (inResumeTopActivity) {
            // Don't even start recursing.
            return false;
        }

        boolean result = false;
        try {
            // Protect against recursion.
            inResumeTopActivity = true;
            result = resumeTopActivityInnerLocked(prev, options);
        } finally {
            inResumeTopActivity = false;
        }
        return result;
    }

?

? 不要有情緒逗宜,繼續(xù)看resumeTopActivityInnerLocked(prev, options);這個方法太長了,我分析了一整天空骚,終于所有體會吧纺讲。這個方法最終的作用是將啟動者activity的生命周期變成paused,這樣之后被啟動的activity的實例創(chuàng)建了之后才能順利的resumed囤屹。我們來看部分代碼:

// Find the first activity that is not finishing.
        //找出棧頂中第一個沒有在被finish的activity,既我們要啟動的actiivty
        ActivityRecord next = topRunningActivityLocked(null);

        // Remember how we'll process this pause/resume situation, and ensure
        // that the state is reset however we wind up proceeding.
        final boolean userLeaving = mStackSupervisor.mUserLeaving;
        mStackSupervisor.mUserLeaving = false;

        final TaskRecord prevTask = prev != null ? prev.task : null;
        //如果整個stack里面是空的熬甚,那么直接啟動launcher
        if (next == null) {
            // There are no more activities!  Let's just start up the
            // Launcher...
            ActivityOptions.abort(options);
            if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: No more activities go home");
            if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
            // Only resume home if on home display
            final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack() ?
                    HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();
            //直接resume系統(tǒng)ActivityStack里面的根activity(Launcher)
            return isOnHomeDisplay() &&
                    mStackSupervisor.resumeHomeStackTask(returnTaskType, prev);
        }

? 在這里,next這個變量很關(guān)鍵牺丙。它的注釋說的是第一個沒有正在被銷毀的activity则涯,顯然我們要被啟動的activity符合這個條件。并且如果這個應(yīng)用級別的stack是空的冲簿,也就是說現(xiàn)在應(yīng)該跳轉(zhuǎn)到系統(tǒng)級別的stack去粟判,也就是顯示系統(tǒng)桌面。

// If the top activity is the resumed one, nothing to do.
        //如果被啟動的activity就是當前處理Resumed狀態(tài)的activity的話峦剔,就什么不做档礁。(一個activity啟動自己就是這種情況)
        if (mResumedActivity == next && next.state == ActivityState.RESUMED &&
                    mStackSupervisor.allResumedActivitiesComplete()) {
            // Make sure we have executed any pending transitions, since there
            // should be nothing left to do at this point.
            mWindowManager.executeAppTransition();
            mNoAnimActivities.clear();
            ActivityOptions.abort(options);
            if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Top activity resumed " + next);
            if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();

            // Make sure to notify Keyguard as well if it is waiting for an activity to be drawn.
            mStackSupervisor.notifyActivityDrawnForKeyguard();
            return false;
        }

?

? 我注釋說的很清楚了,如果要啟動的activity已經(jīng)是resumed了吝沫,就什么都不做呻澜。因為這就是一個當前resumed的activity啟動它自己。

// If we are sleeping, and there is no resumed activity, and the top
        // activity is paused, well that is the state we want.
        //如果系統(tǒng)正在休眠惨险,并且當前最上層的activity都已經(jīng)是paused狀態(tài)了(top activity就是我們要啟動的activity)羹幸。那就是完美的狀態(tài)。
        if (mService.isSleepingOrShuttingDown()
                && mLastPausedActivity == next
                && mStackSupervisor.allPausedActivitiesComplete()) {
            // Make sure we have executed any pending transitions, since there
            // should be nothing left to do at this point.
            mWindowManager.executeAppTransition();
            mNoAnimActivities.clear();
            ActivityOptions.abort(options);
            if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Going to sleep and all paused");
            if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
            return false;
        }

? 如果系統(tǒng)正在休眠辫愉,并且當前最上層的activity都已經(jīng)是paused狀態(tài)了(top activity就是我們要啟動的activity)栅受。那就是完美的狀態(tài)。

// If we are currently pausing an activity, then don't do anything
        // until that is done.
        if (!mStackSupervisor.allPausedActivitiesComplete()) {
            if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG,
                                                                     /  "resumeTopActivityLocked: Skip resume: some activity pausing.");
            if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
            return false;
        }

? 如果我們的app里面正在暫停某個activity,那么我們什么都不要做等這個做完屏镊,因為暫停activity的過程是串行的依疼,必須要一個一個按順序的來。不能同時來而芥,我認為原因就是因為客戶端調(diào)用遠程服務(wù)的過程的時候本地的客戶端所在線程會被掛起

/ We need to start pausing the current activity so the top one
        // can be resumed...
        //先把現(xiàn)在的當前還是resumed的activity pause了律罢,這樣新加進來的activity才能resume」髫ぃ基礎(chǔ)知識
        boolean dontWaitForPause = (next.info.flags&ActivityInfo.FLAG_RESUME_WHILE_PAUSING) != 0;
        //開始暫定現(xiàn)在stack里面所有的activity
        boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, true, dontWaitForPause);
        if (mResumedActivity != null) {
            //開始pausing當前的所有activity误辑,并且返回一個是否暫定成功的結(jié)果回來
            pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);
            if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Pausing " + mResumedActivity);
        }

? 這里就是在做把當前啟動者activity給pause掉,即至于為什么要這么做骄酗。稀余。不用我多說了吧。

? startPausingLocked(userLeaving, false, true, dontWaitForPause);這個函數(shù)跟著看下去就是通過AMS來暫停activity的過程趋翻。這個就不多說了睛琳,大同小異。

最終在函數(shù)的末尾會又調(diào)用ActivityStackSupervisor的startSpecificActivityLocked(next, true, true);方法踏烙。這個方法的源碼如下:

void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
        // Is this activity's application already running?
      //注意了师骗,這里的app之后會用到,因為app.thread就是獲得了applicationthread實例讨惩!
        ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);

        r.task.stack.setLaunchTime(r);

        if (app != null && app.thread != null) {
            try {
                if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
                        || !"android".equals(r.info.packageName)) {
                    // Don't add this if it is a platform component that is marked
                    // to run in multiple processes, because this is actually
                    // part of the framework so doesn't make sense to track as a
                    // separate apk in the process.
                    app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
                            mService.mProcessStats);
                }
              //將app辟癌,信息完整的要啟動的ActivityRecord類的實例傳到另一個方法里面去
                realStartActivityLocked(r, app, andResume, checkConfig);
                return;
            } catch (RemoteException e) {
                Slog.w(TAG, "Exception when starting activity "
                        + r.intent.getComponent().flattenToShortString(), e);
            }

            // If a dead object exception was thrown -- fall through to
            // restart the application.
        }

        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
    }

繼續(xù)跟進這個realStartActivityLocked()(真正啟動activity的過程在這里):

final boolean realStartActivityLocked(ActivityRecord r,
            ProcessRecord app, boolean andResume, boolean checkConfig)
            throws RemoteException {

        r.startFreezingScreenLocked(app, 0);
        if (false) Slog.d(TAG, "realStartActivity: setting app visibility true");
        mWindowManager.setAppVisibility(r.appToken, true);

        // schedule launch ticks to collect information about slow apps.
        r.startLaunchTickingLocked();

        // Have the window manager re-evaluate the orientation of
        // the screen based on the new activity order.  Note that
        // as a result of this, it can call back into the activity
        // manager with a new orientation.  We don't care about that,
        // because the activity is not currently running so we are
        // just restarting it anyway.
        if (checkConfig) {
            Configuration config = mWindowManager.updateOrientationFromAppTokens(
                    mService.mConfiguration,
                    r.mayFreezeScreenLocked(app) ? r.appToken : null);
            mService.updateConfigurationLocked(config, r, false, false);
        }

        r.app = app;
        app.waitingToKill = null;
        r.launchCount++;
        r.lastLaunchTime = SystemClock.uptimeMillis();

        if (localLOGV) Slog.v(TAG, "Launching: " + r);

        int idx = app.activities.indexOf(r);
        if (idx < 0) {
            app.activities.add(r);
        }
        mService.updateLruProcessLocked(app, true, null);
        mService.updateOomAdjLocked();

        final ActivityStack stack = r.task.stack;
        try {
            if (app.thread == null) {
                throw new RemoteException();
            }
            List<ResultInfo> results = null;
            List<Intent> newIntents = null;
            if (andResume) {
                results = r.results;
                newIntents = r.newIntents;
            }

...省略代碼

  //通過applicaitonthread調(diào)用客戶端binder實體的方法。
            app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                    System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
                    r.compat, r.task.voiceInteractor, app.repProcState, r.icicle, r.persistentState,
                    results, newIntents, !andResume, mService.isNextTransitionForward(),
                    profilerInfo);

      ...省略代碼

        return true;
    }

? 這里面兩個很重要的參數(shù)荐捻,一個是ActivityRecord黍少,一個是app。前者就是在ActivityStack里面轉(zhuǎn)了一圈之后得出來的最終要啟動的Activity的信息記錄類处面。后者就是用來獲得ApplicationThread來通知客戶端拿這個ActivityRecord去管理你的activity的生命周期吧厂置!相當于AMS給了ActivityThread一個任務(wù),讓后者去執(zhí)行魂角。同樣昵济,這也是一個IPC的過程。最終調(diào)用鏈繞了好大一圈終于又回到了ApplicaitonThread野揪。

? 值得一提的是访忿,凡是schedule開頭的函數(shù)都是通過handler來做線程調(diào)度的,不服來辯斯稳。我們點進去

public final void scheduleResumeActivity(IBinder token, int processState,
                boolean isForward, Bundle resumeArgs) {
            updateProcessState(processState, false);
            sendMessage(H.RESUME_ACTIVITY, token, isForward ? 1 : 0);
        }

? 果然用handler發(fā)送了一個message海铆。我們來看handler的處理會最終調(diào)用handlerLaunchActivity方法:

Activity a = performLaunchActivity(r, customIntent);

        if (a != null) {
            r.createdConfig = new Configuration(mConfiguration);
            Bundle oldState = r.state;
            handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed);

? 可以看到activity的實例是由performLaunchActivity方法生成的。

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");

      //獲得一些基本信息
        ActivityInfo aInfo = r.activityInfo;
        if (r.packageInfo == null) {
            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                    Context.CONTEXT_INCLUDE_CODE);
        }

        ComponentName component = r.intent.getComponent();
        if (component == null) {
            component = r.intent.resolveActivity(
                mInitialApplication.getPackageManager());
            r.intent.setComponent(component);
        }

        if (r.activityInfo.targetActivity != null) {
            component = new ComponentName(r.activityInfo.packageName,
                    r.activityInfo.targetActivity);
        }

      //通過Instrumentation利用類加載器來生成一個activity實例
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            activity = mInstrumentation.newActivity(
                    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);
            }
        }

      //嘗試生成application
        try {
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);


          //創(chuàng)建contextImpl對象挣惰,并且調(diào)用activity的attach()方法來進行一些activity初始化
            if (activity != null) {
                Context appContext = createBaseContextForActivity(r, activity);
                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                Configuration config = new Configuration(mCompatConfiguration);

              //設(shè)置activity的theme
                int theme = r.activityInfo.getThemeResource();
                if (theme != 0) {
                    activity.setTheme(theme);
                }

                activity.mCalled = false;
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
            mActivities.put(r.token, r);


        return activity;
    }

? 做了這些事情

  • 從ActivityClientRecord中獲取獲取組件信息
  • 通過Instrumentation創(chuàng)建Activity對象
  • 通過LoadApk的makeApplication創(chuàng)建application游添,這個方法有興趣自己去看系草,就是一個單例而已。
  • 創(chuàng)建contextImpl對象唆涝,并且調(diào)用activity的attach()方法來進行一些activity初始化
  • 調(diào)用activity的onCreat()方法

完成整個過程調(diào)用 !4奖妗@群ā!

結(jié)束語

? 系統(tǒng)源碼看起來確實感覺自己置身茫茫大海一樣赏枚,特別是要去找一些不理解的問題的時候亡驰。比如到底是被啟動的activity的ActivityRecord實例先添加進去還是在實例創(chuàng)建了之后才添加進去,這個問題我看源碼著了一天才還沒有什么結(jié)果饿幅,后來在別人的幫助和查閱老羅的資料才找到問題所在凡辱。挺不錯的一次過程,確實細節(jié)不必死扣栗恩,但是有些基本問題不懂的話還是應(yīng)該去探究一下透乾。

版權(quán)聲明:本文為博主原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載磕秤。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末乳乌,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子市咆,更是在濱河造成了極大的恐慌汉操,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蒙兰,死亡現(xiàn)場離奇詭異磷瘤,居然都是意外死亡,警方通過查閱死者的電腦和手機搜变,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進店門采缚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人痹雅,你說我怎么就攤上這事仰担。” “怎么了绩社?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵摔蓝,是天一觀的道長。 經(jīng)常有香客問我愉耙,道長贮尉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任朴沿,我火速辦了婚禮猜谚,結(jié)果婚禮上败砂,老公的妹妹穿的比我還像新娘。我一直安慰自己魏铅,他們只是感情好昌犹,可當我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著览芳,像睡著了一般斜姥。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上沧竟,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天铸敏,我揣著相機與錄音,去河邊找鬼悟泵。 笑死杈笔,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的糕非。 我是一名探鬼主播蒙具,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼峰弹!你這毒婦竟也來了店量?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤鞠呈,失蹤者是張志新(化名)和其女友劉穎融师,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蚁吝,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡旱爆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了窘茁。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片怀伦。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖山林,靈堂內(nèi)的尸體忽然破棺而出房待,到底是詐尸還是另有隱情,我是刑警寧澤驼抹,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布桑孩,位于F島的核電站,受9級特大地震影響框冀,放射性物質(zhì)發(fā)生泄漏流椒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一明也、第九天 我趴在偏房一處隱蔽的房頂上張望宣虾。 院中可真熱鬧惯裕,春花似錦、人聲如沸绣硝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽域那。三九已至咙边,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間次员,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工王带, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留淑蔚,地道東北人。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓愕撰,卻偏偏與公主長得像刹衫,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子搞挣,可洞房花燭夜當晚...
    茶點故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內(nèi)容