從源碼的角度看Activity是如何啟動(dòng)的

歡迎訪問我的個(gè)人博客煌妈,原文鏈接:http://wensibo.top/2017/07/05/Activity/ ,未經(jīng)允許不得轉(zhuǎn)載宣羊!
大家好璧诵,今天想與大家一起分享的是Activity。我們平時(shí)接觸的最多的就是Activity了仇冯,作為四大組件中最為重要的老大之宿,Activity究竟是如何啟動(dòng)的呢?這篇文章將會(huì)從源碼的角度為大家進(jìn)行全方位的解析苛坚,為了方便大家理解整個(gè)的過程比被,我會(huì)用流程圖的方式將整個(gè)過程串起來,希望對(duì)大家有所幫助泼舱。

開始吧等缀!

一般我們啟動(dòng)Activity有兩種方法,這里我就不再詳細(xì)說這兩種方法的用法了娇昙,不過他們都是調(diào)用了同樣的一個(gè)邏輯startActivity尺迂。所以我們分析Activity的啟動(dòng)流程就從這個(gè)方法開始。

 public void startActivity(Intent intent, @Nullable Bundle options) {
    if (options != null) {
        startActivityForResult(intent, -1, options);
    } else {
        startActivityForResult(intent, -1);
    }
}

可以看到盡管startActivity()有多種重載方式冒掌,但是最終調(diào)用的還是startActivityForResult噪裕,所以我們只需要看startActivityForResult里面的實(shí)現(xiàn)邏輯即可。這里需要注意的一點(diǎn)就是調(diào)用了startActivityForResult方法時(shí)傳入的一個(gè)參數(shù)為-1股毫,為什么是-1呢膳音?還記得我們?nèi)绻枰乱粋€(gè)Activity返回?cái)?shù)據(jù)給目前這個(gè)Activity的時(shí)候都是調(diào)用startActivityForResult方法,不會(huì)去調(diào)用startActivity铃诬,因?yàn)閟tartActivity盡管最后還是調(diào)用startActivityForResult祭陷,但是他設(shè)置了requestCode參數(shù)為-1,二在startActivityForResult方法中會(huì)判斷requestCode是否大于等于0氧急,如果小于0就不會(huì)返回結(jié)果颗胡,因此我們都會(huì)選擇startActivityForResult方法以取回結(jié)果,并且設(shè)置其code參數(shù)大于等于0吩坝。下面我們來看看startActivityForResult的實(shí)現(xiàn):

public void startActivityForResult(
@RequiresPermission Intent intent, int requestCode,@Nullable Bundle options) {
        //mParent是一個(gè)Activity對(duì)象毒姨,表示該Activity是否由父Activity啟動(dòng)
    if (mParent == null) {
        options = transferSpringboardActivityOptions(options);
        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());
        }
        //這里就是判斷requestCode的邏輯
        if (requestCode >= 0) {
            mStartedActivity = true;
        }

        cancelInputsAndStartExitTransition(options);
    } else {
        if (options != null) {
            mParent.startActivityFromChild(this, intent, requestCode, options);
        } else {
            mParent.startActivityFromChild(this, intent, requestCode);
        }
    }
}

在startActivityForResult方法中,首先會(huì)判斷該Activity是否由父Activity啟動(dòng)钉寝,即mParent弧呐,如果他是第一個(gè)Activity闸迷,就會(huì)調(diào)用Instrumentation的execStartActivity方法,這里再看一下判斷requestCode的邏輯:

if (requestCode >= 0) {
    mStartedActivity = true;
}

可以看到在這里確實(shí)判斷了requestCode的大小,大于等于0的時(shí)候才會(huì)返回結(jié)果俘枫,否則是不會(huì)的腥沽。
繼續(xù)說回execStartActivity方法,這里就是正真執(zhí)行Activity啟動(dòng)的操作鸠蚪,解釋一下他的幾個(gè)參數(shù):

  • this今阳,為啟動(dòng)Activity的對(duì)象
  • mMainThread.getApplicationThread(),為Binder對(duì)象茅信,是主進(jìn)程的context對(duì)象
  • token盾舌,也是一個(gè)Binder對(duì)象,指向了服務(wù)端一個(gè)ActivityRecord對(duì)象
  • target蘸鲸,為啟動(dòng)的Activity
  • intent妖谴,啟動(dòng)的Intent對(duì)象
  • requestCode,請(qǐng)求碼
  • options酌摇,參數(shù)

這里的第一個(gè)Binder對(duì)象在我們的整個(gè)分析過程中將扮演者非常重要的作用膝舅,如果你對(duì)Binder不熟悉的話,請(qǐng)到這里了解有關(guān)Binder機(jī)制的內(nèi)容窑多。
接下來是execStartActivity方法:

public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, Activity target,
        Intent intent, int requestCode, Bundle options) {
    ...
    try {
        intent.migrateExtraStreamToClipData();
        intent.prepareToLeaveProcess();
        int result = ActivityManagerNative.getDefault()
            .startActivity(whoThread, who.getBasePackageName(), intent,
                    intent.resolveTypeIfNeeded(who.getContentResolver()),
                    token, target != null ? target.mEmbeddedID : null,
                    requestCode, 0, null, options);
        checkStartActivityResult(result, intent);
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
    return null;
}

這里最重要的就是調(diào)用了ActivityManagerNative.getDefault().startActivity()仍稀,但是ActivityManagerNative.getDefault()是什么東西呢?我們繼續(xù)看getDefault()的源碼:

static public IActivityManager getDefault() {
    return gDefault.get();
}


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;
    }
};

可以看到其中聲明了一個(gè)Singleton封裝類怯伊,其類型是IActivityManager琳轿,注意到其中調(diào)用了asInterface方法,接著看他做了什么耿芹?

static public IActivityManager asInterface(IBinder obj) {
    if (obj == null) {
        return null;
    }
    IActivityManager in =
        (IActivityManager)obj.queryLocalInterface(descriptor);
    if (in != null) {
        return in;
    }

    return new ActivityManagerProxy(obj);
}


//ActivityManagerProxy:startActivity
public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
            String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        data.writeString(callingPackage);
        intent.writeToParcel(data, 0);
        data.writeString(resolvedType);
        data.writeStrongBinder(resultTo);
        data.writeString(resultWho);
        data.writeInt(requestCode);
        data.writeInt(startFlags);
        if (profilerInfo != null) {
            data.writeInt(1);
            profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
        } else {
            data.writeInt(0);
        }
        if (options != null) {
            data.writeInt(1);
            options.writeToParcel(data, 0);
        } else {
            data.writeInt(0);
        }
        mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
        reply.readException();
        int result = reply.readInt();
        reply.recycle();
        data.recycle();
        return result;
    }

可以看到asInterface返回了一個(gè)ActivityManagerProxy對(duì)象崭篡,也就是說ActivityManagerNative.getDefault()返回的就是一個(gè)ActivityManagerProxy對(duì)象,通過之前的BInder機(jī)制的文章我們可以知道Proxy是運(yùn)行在客戶端的吧秕,客戶端通過將參數(shù)寫入Proxy類琉闪,接著Proxy就會(huì)通過Binder去遠(yuǎn)程調(diào)用服務(wù)端的具體方法,因此砸彬,我們只是借用ActivityManagerProxy來調(diào)用ActivityManagerService的方法颠毙,他們之間的關(guān)系如下所示:

通信方式

到目前為止Activity的啟動(dòng)流程就是如下所示了,可以看到Activity的啟動(dòng)邏輯來到了AMS中砂碉。

在AMS中啟動(dòng)Activity

@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) {
    return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
        resultWho, requestCode, startFlags, profilerInfo, options,
        UserHandle.getCallingUserId());
}

@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.
    return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
            resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
            profilerInfo, null, null, options, false, userId, null, null);
}

在startActivity中直接調(diào)用了startActivityAsUser方法蛀蜜,而在startActivityAsUser中則是調(diào)用mStackSupervisor.startActivityMayWait方法:

final int startActivityLocked(IApplicationThread caller,
    Intent intent, String resolvedType, ActivityInfo aInfo,
    IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
    IBinder resultTo, String resultWho, int requestCode,
    int callingPid, int callingUid, String callingPackage,
    int realCallingPid, int realCallingUid, int startFlags, Bundle options,
    boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
    ActivityContainer container, TaskRecord inTask) {
    int err = ActivityManager.START_SUCCESS;

    ...
    err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
        startFlags, true, options, inTask);

    ...
    return err;
    }

這個(gè)方法中主要構(gòu)造了ActivityManagerService端的Activity對(duì)象:ActivityRecord,并根據(jù)Activity的啟動(dòng)模式執(zhí)行了相關(guān)邏輯增蹭。然后調(diào)用了startActivityUncheckedLocked方法滴某,而在startActivityUncheckedLocked中則調(diào)用了startActivityUncheckedLocked方法,startActivityUncheckedLocked方法則會(huì)調(diào)用startActivityLocked方法,startActivityLocked又會(huì)調(diào)用resumeTopActivitiesLocked方法霎奢,其最后調(diào)用了resumeTopActivityLocked方法户誓。
經(jīng)過一系列的調(diào)用之后,最終來到了startPausingLocked方法幕侠,它會(huì)執(zhí)行Activity的onPause方法帝美,從而結(jié)束當(dāng)前的Activity。
首先來看startPausingLocked方法:

final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, boolean resuming,boolean dontWait) {
    ...
    if (prev.app != null && prev.app.thread != null) {
        if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev);
        try {
            EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
                    prev.userId, System.identityHashCode(prev),
                    prev.shortComponentName);
            mService.updateUsageStats(prev, false);
            prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
                    userLeaving, prev.configChangeFlags, dontWait);
        } catch (Exception e) {
            // Ignore exception, if process died other code will cleanup.
            Slog.w(TAG, "Exception thrown during pause", e);
            mPausingActivity = null;
            mLastPausedActivity = null;
            mLastNoHistoryActivity = null;
        }
    } else {
        mPausingActivity = null;
        mLastPausedActivity = null;
        mLastNoHistoryActivity = null;
    }
    ...
}

這里有一個(gè)很重要的地方就是prev.app.thread晤硕,其實(shí)他就是一個(gè)IApplicationThread類型的對(duì)象悼潭,而ApplicationThread則是ActivityThread的一個(gè)內(nèi)部類,它繼承了IApplicationThread舞箍,并且都是Binder對(duì)象女责,所以說Appcation是一個(gè)客戶端,而ActivityThread中是一個(gè)服務(wù)端,到現(xiàn)在為止创译,Activity的調(diào)用來到了ActivityThread中,如下圖所示:

在ActivityThread中pause掉當(dāng)前Activity

在ActivityThread中則是調(diào)用了schedulePauseActivity來執(zhí)行pause操作:

public final void schedulePauseActivity(IBinder token, boolean finished,boolean userLeaving, int configChanges, boolean dontReport) {
    sendMessage(
        finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
        token,
        (userLeaving ? 1 : 0) | (dontReport ? 2 : 0),
        configChanges);
}

可以看到在schedulePauseActivity中則是通過handler來發(fā)送消息墙基,消息類型為PAUSE_ACTIVITY_FINISHING软族,那接下來就應(yīng)該看收到消息之后如何來處理了,

private void handlePauseActivity(IBinder token, boolean finished,
            boolean userLeaving, int configChanges, boolean dontReport) {
    ActivityClientRecord r = mActivities.get(token);
    if (r != null) {
        //Slog.v(TAG, "userLeaving=" + userLeaving + " handling pause of " + r);
        if (userLeaving) {
            performUserLeavingActivity(r);
        }

        r.activity.mConfigChangeFlags |= configChanges;
        performPauseActivity(token, finished, r.isPreHoneycomb());

        // Make sure any pending writes are now committed.
        if (r.isPreHoneycomb()) {
            QueuedWork.waitToFinish();
        }

        // Tell the activity manager we have paused.
        if (!dontReport) {
            try {
                ActivityManagerNative.getDefault().activityPaused(token);
            } catch (RemoteException ex) {
            }
        }
        mSomeActivitiesChanged = true;
    }
}

可以看到在方法內(nèi)部通過調(diào)用performPauseActivity方法來實(shí)現(xiàn)對(duì)當(dāng)前Activity的onPause生命周期方法的回調(diào)残制,具體是調(diào)用了performPause方法:

final void performPause() {
    mDoReportFullyDrawn = false;
    mFragments.dispatchPause();
    mCalled = false;
    onPause();
    mResumed = false;
    if (!mCalled && getApplicationInfo().targetSdkVersion
            >= android.os.Build.VERSION_CODES.GINGERBREAD) {
        throw new SuperNotCalledException(
                "Activity " + mComponent.toShortString() +
                " did not call through to super.onPause()");
    }
    mResumed = false;
}

可以看到最終是調(diào)用了Activity的onPause()方法立砸,接著我們回到handlePauseActivity的第二個(gè)方法ActivityManagerNative.getDefault().activityPaused(token),這是應(yīng)用進(jìn)程告訴服務(wù)進(jìn)程初茶,當(dāng)前的Activity已經(jīng)執(zhí)行完成onPause方法了颗祝,其最后會(huì)調(diào)用completePauseLocked方法:

private void completePauseLocked(boolean resumeNext) {
    ...
    if (resumeNext) {
        final ActivityStack topStack = mStackSupervisor.getFocusedStack();
        if (!mService.isSleepingOrShuttingDown()) {
            mStackSupervisor.resumeTopActivitiesLocked(topStack, prev, null);
        } else {
            mStackSupervisor.checkReadyForSleepLocked();
            ActivityRecord top = topStack.topRunningActivityLocked(null);
            if (top == null || (prev != null && top != prev)) {
                // If there are no more activities available to run,
                // do resume anyway to start something.  Also if the top
                // activity on the stack is not the just paused activity,
                // we need to go ahead and resume it to ensure we complete
                // an in-flight app switch.
                mStackSupervisor.resumeTopActivitiesLocked(topStack, null, null);
            }
        }
    }
}

可以看到經(jīng)過了一系列的邏輯之后,又調(diào)用了resumeTopActivitiesLocked方法恼布,而在該方法中則是調(diào)用了startSpecificActivityLocked 來啟動(dòng)新的Activity螺戳。來看看目前的流程圖:


啟動(dòng)新的Activity

在startSpecificActivityLocked方法中,其實(shí)現(xiàn)細(xì)節(jié)則是和調(diào)用Activity的pause方法一樣折汞,都是通過Handler機(jī)制倔幼,發(fā)送一個(gè)啟動(dòng)Activity的消息,接著處理該消息最后啟動(dòng)Activity爽待。其調(diào)用的是performLaunchActivity方法:

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);
            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);
            }
        }
        ...

        activity.mCalled = false;
        if (r.isPersistable()) {
           mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
        } else {
           mInstrumentation.callActivityOnCreate(activity, r.state);
        }
        ...
        if (!r.activity.mFinished) {
                    activity.performStart();
                    r.stopped = false;
                }
        ...
        return activity;
    }

可以看到最終的Activity對(duì)象終于創(chuàng)建出來了损同,可以看到其過程是使用反射機(jī)制創(chuàng)建的,而反射機(jī)制在Android系統(tǒng)中的應(yīng)用也是隨處可見鸟款。在接下來的過程中還會(huì)繼續(xù)執(zhí)行Activity的onCreate等一系列的生命周期方法膏燃。
最后再來看一下整個(gè)過程最終的流程圖:


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市何什,隨后出現(xiàn)的幾起案子组哩,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,222評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件禁炒,死亡現(xiàn)場離奇詭異而咆,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)幕袱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,455評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門暴备,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人们豌,你說我怎么就攤上這事涯捻。” “怎么了望迎?”我有些...
    開封第一講書人閱讀 157,720評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵障癌,是天一觀的道長。 經(jīng)常有香客問我辩尊,道長涛浙,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,568評(píng)論 1 284
  • 正文 為了忘掉前任摄欲,我火速辦了婚禮轿亮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘胸墙。我一直安慰自己我注,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,696評(píng)論 6 386
  • 文/花漫 我一把揭開白布迟隅。 她就那樣靜靜地躺著但骨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪智袭。 梳的紋絲不亂的頭發(fā)上奔缠,一...
    開封第一講書人閱讀 49,879評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音补履,去河邊找鬼添坊。 笑死,一個(gè)胖子當(dāng)著我的面吹牛箫锤,可吹牛的內(nèi)容都是我干的贬蛙。 我是一名探鬼主播,決...
    沈念sama閱讀 39,028評(píng)論 3 409
  • 文/蒼蘭香墨 我猛地睜開眼谚攒,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼阳准!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起馏臭,我...
    開封第一講書人閱讀 37,773評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤野蝇,失蹤者是張志新(化名)和其女友劉穎讼稚,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體绕沈,經(jīng)...
    沈念sama閱讀 44,220評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡锐想,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,550評(píng)論 2 327
  • 正文 我和宋清朗相戀三年巍实,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了赖歌。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片于置。...
    茶點(diǎn)故事閱讀 38,697評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡目木,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出朦促,到底是詐尸還是另有隱情痴颊,我是刑警寧澤樱调,帶...
    沈念sama閱讀 34,360評(píng)論 4 332
  • 正文 年R本政府宣布惜傲,位于F島的核電站洽故,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏盗誊。R本人自食惡果不足惜时甚,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,002評(píng)論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望哈踱。 院中可真熱鬧撞秋,春花似錦、人聲如沸嚣鄙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,782評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽哑子。三九已至,卻和暖如春肌割,著一層夾襖步出監(jiān)牢的瞬間卧蜓,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,010評(píng)論 1 266
  • 我被黑心中介騙來泰國打工把敞, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留弥奸,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,433評(píng)論 2 360
  • 正文 我出身青樓奋早,卻偏偏與公主長得像盛霎,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子耽装,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,587評(píng)論 2 350

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