Android Activity 的一生

android

前言

接觸過Android開發(fā)的同學(xué)都知道Activity,Activity作為Android四大組件之一揭北,使用頻率高。簡單來說Activity提供了一個顯示界面,讓用戶進行各種操作鹰溜,本文主要分為以下三個部分:Activity的生命周期,啟動模式丁恭,以及Activity的工作過程曹动。本文主要目的是幫自己梳理Activity的相關(guān)問題,疏漏之處歡迎指出牲览。

說明:本文中的源碼都是基于Android-25版本墓陈。

Activity生命周期

生命周期

首先給出Activity的完整生命周期,如下圖所示:

image

圖片來源Android開發(fā)者官網(wǎng)

看完了完整的生命周期,我們再分別簡單介紹單個生命周期含義贡必。

  • onCreate:表示Activity正在被創(chuàng)建熬的,做一些初始化工作,如加載布局文件赊级,對一些變量或者控件進行初始化
  • onStart:表示Activity正在啟動押框,此時Activity已經(jīng)可見了,但還無法和用戶交互
  • onResume:表示Activity已經(jīng)在前臺理逊,可以和用戶交互了
  • onPause:表示Activity正在停止橡伞,此時可以進行一些輕量級的存儲數(shù)據(jù)和停止動畫等工作,但不能太耗時晋被,否則會影響到新Activity的顯示兑徘,Android指定如果onPause在500ms內(nèi)沒有執(zhí)行完畢的話就會強制關(guān)閉Activity。某些極端情況下羡洛,這個時候Activity會回到當(dāng)前Activity挂脑,此時onResume會被執(zhí)行,很難重現(xiàn)這一情形
  • onStop:表示Activity即將停止欲侮,此時Activity已經(jīng)不可見了崭闲,但是Activity對象還存在內(nèi)存中,沒有被銷毀威蕉,這個階段也主要做一些資源回收的工作刁俭,不能太耗時
  • onDestory:表示Activity即將被銷毀,可以做一些回收工作和最終的資源釋放韧涨,最后一個回調(diào)方法
  • onRestart:表示Activity重新啟動牍戚,當(dāng)前Activity從不可見重新變?yōu)榭梢姇r會調(diào)用onRestart,這種情況一般是用戶的行為導(dǎo)致的虑粥,比如:用戶按Home鍵切換到桌面或者打開了一個新的Activity

三個問題

onCreate如孝,onStart和onResume之間的區(qū)別?

  • onCreate時Activity還不可見,onStart已經(jīng)可見娩贷,還不在前臺第晰,onResume已經(jīng)出現(xiàn)在前臺
  • onCreate方法只在Activity創(chuàng)建時執(zhí)行一次,而onStart方法在Activity的切換以及按Home鍵返回桌面再切回應(yīng)用的過程中被多次調(diào)用育勺,因此數(shù)據(jù)恢復(fù)在onStart方法中比較合適但荤,onResume方法可以做一些開啟動畫和獨占設(shè)備的操作

onPause,onStop和onDestroy之間的區(qū)別?

  • onPause時Activity還可見涧至,onStop已經(jīng)不可見,但Activity對象還存在內(nèi)存中桑包,onDestroy后Activity對象就不存在了
  • 內(nèi)存不足時南蓬,可能不會執(zhí)行onStop方法,因此程序狀態(tài)保存,停止動畫赘方,存儲數(shù)據(jù)等操作最好放在onPause

切換Activity時生命周期執(zhí)行順序

假設(shè)當(dāng)前Activity為A烧颖,此時用戶打開Activity B,那么A和B的生命周期的執(zhí)行順序為:

image

為了驗證生命周期執(zhí)行順序窄陡,我們寫個例子實測炕淮,MainActivity中單擊按鈕跳轉(zhuǎn)到SecondActivity,然后在相應(yīng)的生命周期中輸出日志跳夭,如下:

public class MainActivity extends Activity {

    private static final String TAG = "MainActivity";

    ... 

    @Override
    protected void onPause(){
        super.onPause();
        Log.d(TAG,"onPause");
    }

    @Override
    protected void onStop(){
        super.onStop();
        Log.d(TAG,"onStop");
    }
}

public class SecondActivity extends Activity {

    private static final String TAG = "SecondActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG,"onCreate");
    }

    @Override
    protected void onStart(){
        super.onStart();
        Log.d(TAG,"onStart");
    }

    @Override
    protected void onResume(){
        super.onResume();
        Log.d(TAG,"onResume");
    }
}

日志結(jié)果如下:

08-31 12:36:36.086 3825-3825/com.sakura.activity D/MainActivity: onPause
08-31 12:36:36.093 3825-3825/com.sakura.activity D/SecondActivity: onCreate
08-31 12:36:36.093 3825-3825/com.sakura.activity D/SecondActivity: onStart
08-31 12:36:36.094 3825-3825/com.sakura.activity D/SecondActivity: onResume
08-31 12:36:36.517 3825-3825/com.sakura.activity D/MainActivity: onStop

那么為什么會有這樣的生命周期執(zhí)行順序呢涂圆?Android官方文檔對onPause的解釋為:不能在onPause中做重量級的操作,因為必須onPause執(zhí)行完成以后新Activity才能Resume币叹,同時我在分析Activity啟動源過程中碼也得到了相同結(jié)論润歉。

Activity保存狀態(tài)

當(dāng) Activity 暫停或停止時颈抚,Activity 的狀態(tài)會得到保留踩衩。因為當(dāng) Activity 暫停或停止時贩汉,Activity 對象仍保留在內(nèi)存中 驱富,有關(guān)其成員和當(dāng)前狀態(tài)的所有信息仍處于活動狀態(tài)。
但是當(dāng)系統(tǒng)的配置發(fā)生變化(屏幕旋轉(zhuǎn)匹舞,語言變換等)時萌朱,Activity 被銷毀,系統(tǒng)回調(diào) onSaveInstanceState() 方法對有關(guān) Activity 狀態(tài)的信息進行保存策菜,系統(tǒng)會向該方法傳遞一個 Bundle晶疼,可以在其中使用 putString()putInt() 等方法以名稱-值對形式保存有關(guān) Activity 狀態(tài)的信息。當(dāng) Activity 重建時將 Bundle 同時傳遞給 onCreate()onRestoreInstanceState() 方法又憨,使用上述任一方法從 Bundle 提取保存的數(shù)據(jù)并恢復(fù)該 Activity 狀態(tài)翠霍。

image

圖片來源Android開發(fā)者官網(wǎng)

onSaveInstanceState()onRestoreInstanceState() 方法中,系統(tǒng)自動為我們做了一定的恢復(fù)工作蠢莺,布局中的每個 View 調(diào)用自己的 onSaveInstanceState() 方法寒匙,讓每個視圖都能保存自身需保存的信息。
每個 View 都有 onSaveInstanceState()onRestoreInstanceState() 方法躏将,具體能恢復(fù)哪些數(shù)據(jù)锄弱,需要查看其源碼。保存和恢復(fù) View 用到了事件委托思想祸憋,從下至上会宪,再從上到下。需要注意的是蚯窥,只有我們?yōu)?View 指定了唯一的ID屬性(android:id)系統(tǒng)才會自動為其在需要時自動保存和恢復(fù)數(shù)據(jù)掸鹅。
通過重寫onSaveInstanceState()onRestoreInstanceState() 實現(xiàn)自定義的數(shù)據(jù)恢復(fù)機制塞帐。
那么 onSaveInstanceState()onRestoreInstanceState() 方法和 Activity 的生命周期的執(zhí)行順序是怎么樣的?
onSaveInstanceState() 方法是在onStop之前巍沙,和onPause沒有既定的時序關(guān)系葵姥, onRestoreInstanceState() 方法是在onStart之后、onResume之前調(diào)用的句携。

Activity啟動模式

默認(rèn)情況下榔幸,當(dāng)我們多次啟動同一個Activity時,系統(tǒng)會創(chuàng)建多個實例并把它們一一放入任務(wù)棧中矮嫉,任務(wù)棧是一種后進先出的棧結(jié)構(gòu)削咆,每按下back鍵就會有一個Activity出棧,直到棾伲空為止态辛。

standard:標(biāo)準(zhǔn)模式

這是系統(tǒng)默認(rèn)的模式,每次啟動一個新的Activity都會重新創(chuàng)建一個新的實例挺尿,不管這個實例已經(jīng)是否存在奏黑。這種模式下,如果A啟動了B(標(biāo)準(zhǔn)模式)编矾,那么B自動進入A所在的任務(wù)棧中熟史。

singleTop:棧頂復(fù)用模式

此種模式下,如果新Activity已經(jīng)位于任務(wù)棧的棧頂窄俏,那么此Activity不會被重新創(chuàng)建蹂匹,同時onNewIntent方法會被調(diào)用,通過此方法的參數(shù)獲取當(dāng)前請求信息凹蜈。而且限寞,此Activity的onCreate,onStart不會被調(diào)用仰坦,因為沒有發(fā)生改變履植。

singleTask:棧內(nèi)復(fù)用模式

此種模式下,只要Activity在一個棧中存在悄晃,那么多次啟動此Activity都不會重新創(chuàng)建實例玫霎,系統(tǒng)會回調(diào)onNewIntent方法。系統(tǒng)會先尋找是否存在A想要的任務(wù)棧妈橄,如果不存在庶近,就重建一個任務(wù)棧,然后創(chuàng)建A的實例放入新任務(wù)棧中眷蚓;如果存在A想要的任務(wù)棧鼻种,再查看是否有Activity實例存在,有的話就把該實例調(diào)到棧頂溪椎,如果實例不存在普舆,則創(chuàng)建A的實例放入任務(wù)棧中恬口。下面舉三種例子說明此種模式運行機制:

  • 目前任務(wù)棧S1中為ABC校读,Activity D以singleTask模式請求啟動沼侣,其需要的任務(wù)棧為S1,那么系統(tǒng)會創(chuàng)建D的實例歉秫,將D放入S1中
  • 目前任務(wù)棧S1中為ABC蛾洛,Activity D以singleTask模式請求啟動,其需要的任務(wù)棧為S2雁芙,那么系統(tǒng)會創(chuàng)建任務(wù)棧S2轧膘,再將D放入S2中
  • 目前任務(wù)棧S1中為ADBC,Activity D以singleTask模式請求啟動兔甘,其需要的任務(wù)棧為S1谎碍,那么系統(tǒng)不會創(chuàng)建D的實例,將D切換到棧頂并調(diào)用其onNewIntent方法洞焙,同時棧內(nèi)所有在D上面的Activity都需要出棧蟆淀,最終的S1為AD

singleInstance:單實例模式

這是一種加強的singleTask模式,除了具有singleTask模式的所有特性外澡匪,具有此種模式的Activity只能單獨位于一個任務(wù)棧中熔任。比如Activity A以singleInstance模式啟動,系統(tǒng)會為其創(chuàng)建一個新的任務(wù)棧唁情,然后A獨自運行在該任務(wù)棧中疑苔,后續(xù)的請求均不會創(chuàng)建新的Activity。

任務(wù)棧

在啟動模式中多次提到Activity的任務(wù)棧甸鸟,默認(rèn)情況下惦费,所有Activity所需任務(wù)棧的名字為應(yīng)用的包名。此外還有一個參數(shù)TaskAffinity抢韭,這個參數(shù)標(biāo)識了Activity所需要的任務(wù)棧的名字薪贫,TaskAffinity屬性主要和singleTask模式或者allowTaskReparenting屬性配對使用。

如何指定Activity啟動模式

  • 第一種是通過AndroidManifest.xml 指定:
<activity android:name=".SecondActivity"
    android:launchMode="singleTask"
    android:label="@string/app_name"/>

  • 第二種是通過在Intent中設(shè)置標(biāo)志位篮绰,比如:
Intent intent = new Intent();
intent.setClass(MainActivity.this, SecondActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

Activity啟動過程源碼分析

聊完了Activity的生命周期及啟動模式后雷,最頭疼的部分來了,那就是一個Activity究竟是如何啟動的呢吠各?以下篇幅結(jié)合源碼一探究竟臀突,撥開云霧見青天。在顯式調(diào)用啟動Activity時贾漏,我們通過以下代碼完成:

Intent intent = new Intent(this, TestActivity.class);
startActivity(intent);

上述代碼便可以啟動一個Activity候学,下面我們便從源頭理清Activity的啟動流程,當(dāng)然我們不可能對所有細(xì)節(jié)描述清楚纵散,需要做的是理清流程梳码,點到為止隐圾。

startActivity/startActivityForResult

我們從Activity的startActivity方法開始分析,讀源碼可知掰茶,startActivity方法有好幾種重載形式暇藏,但最終都調(diào)用了startActivityForResult方法,因此我們重點分析startActivityForResult方法:

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode, @Nullable Bundle options) {
    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());
        }
        if (requestCode >= 0) {
            // If this start is requesting a result, we can avoid making
            // the activity visible until the result is received.  Setting
            // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
            // activity hidden during this time, to avoid flickering.
            // This can only be done when a result is requested because
            // that guarantees we will get information back when the
            // activity is finished, no matter what happens to it.
            mStartedActivity = true;
        }
        cancelInputsAndStartExitTransition(options);
        // TODO Consider clearing/flushing other event sources and events for child windows.
    } else {
        if (options != null) {
            mParent.startActivityFromChild(this, intent, requestCode, options);
        } else {
            // Note we want to go through this method for compatibility with
            // existing applications that may have overridden it.
            mParent.startActivityFromChild(this, intent, requestCode);
        }
    }
}

Instrumentation

我們主要關(guān)注mParent == null這一部分邏輯濒蒋,首先盐碱,mParent是一個Activity對象,表示該Activity是否由父Activity啟動沪伙,如果該Activity是第一個被啟動的瓮顽,那么就會調(diào)用InstrumentationexecStartActivity方法:

public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, Activity target,
        Intent intent, int requestCode, Bundle options) {
    IApplicationThread whoThread = (IApplicationThread) contextThread;
    Uri referrer = target != null ? target.onProvideReferrer() : null;
    if (referrer != null) {
        intent.putExtra(Intent.EXTRA_REFERRER, referrer);
    }
    if (mActivityMonitors != null) {
        synchronized (mSync) {
            final int N = mActivityMonitors.size();
            for (int i=0; i<N; i++) {
                final ActivityMonitor am = mActivityMonitors.get(i);
                if (am.match(who, null, intent)) {
                    am.mHits++;
                    if (am.isBlocking()) {
                        return requestCode >= 0 ? am.getResult() : null;
                    }
                    break;
                }
            }
        }
    }
    try {
        intent.migrateExtraStreamToClipData();
        intent.prepareToLeaveProcess(who);
        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) {
        throw new RuntimeException("Failure from system", e);
    }
    return null;
}

Instrumentation是管理Activity的一個工具類,包括創(chuàng)建和啟動Activity围橡,Activity的生命周期方法都是由Instrumentation這個類來控制暖混,一個進程中只用一個Instrumentation實例。
execStartActivity是真正啟動Activity的操作翁授,下面解釋其參數(shù):

  • who : 待啟動的Activity對象
  • mMainThread.getApplicationThread() : ApplicationThread對象拣播,也是Binder對象
  • mToken :Binder對象,指向服務(wù)端一個ActivityRecord對象
  • target :待啟動的Activity對象
  • intent :啟動的intent對象
  • requestCode :請求碼
  • options :參數(shù)

AMS

再回到execStartActivity方法體中黔漂,其中可以看到真正實現(xiàn)Activity啟動的是ActivityManagerNative.getDefault().startActivity方法诫尽。下面列出了ActivityManagerNative.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;
    }
};

static public IActivityManager asInterface(IBinder obj) {
    if (obj == null) {
        return null;
    }
    IActivityManager in = 
        (IActivityManager)obj.queryLocalInterface(descriptor);
    if (in != null) {
        return in;                        // 同一進程,返回本地對象stub
    }
    return new ActivityManagerProxy(obj); // 跨進程炬守,返回代理對象
}

其中聲明了一個Singleton封裝類牧嫉,類型是IActivityManager,第一次調(diào)用它的get方法它會通過create方法來初始化AMS這個Binder對象减途。其中在asInterface方法中返回了一個IActivityManager類型對象酣藻。
ActivityManagerService(AMS)繼承自ActivityManagerNative,而ActivityManagerNative繼承自Binder并實現(xiàn)了IActivityManager接口鳍置,因此AMS是一個Binder辽剧,同時也是IActivityManager的具體實現(xiàn),ActivityManagerNative.getDefault()其實是一個IActivityManager類型的Binder對象税产,即AMS怕轿。我們理一下上面提到的各種類和接口之間的關(guān)系:

public final class ActivityManagerService extends ActivityManagerNative {...}

public abstract class ActivityManagerNative extends Binder implements IActivityManager {...}

public interface IActivityManager extends IInterface {...}

所以Activity的啟動過程轉(zhuǎn)移到AMS中,下面分析AMSstartActivity方法:

public final int startActivity(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
    return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
            resultWho, requestCode, startFlags, profilerInfo, bOptions,
            UserHandle.getCallingUserId());
}

public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
    enforceNotIsolatedCaller("startActivity");
    userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
            userId, false, ALLOW_FULL_ONLY, "startActivity", null);

    // Android7.0 Acitivty啟動管理類新增ActivityStarter(原本是ActivityStackSupervisor處理該過程)
    return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
            resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
            profilerInfo, null, null, bOptions, false, userId, null, null);
}

ActivityStarter

上述代碼中mActivityStarter是一個ActivityStarter對象辟拷,初始化為:

mActivityStarter = new ActivityStarter(this, mStackSupervisor);

可以看出Activity的啟動過程轉(zhuǎn)移到ActivityStarterstartActivityMayWait方法中撞羽,startActivityMayWait又調(diào)用了startActivityLocked方法:

final int startActivityMayWait(IApplicationThread caller, int callingUid,
        String callingPackage, Intent intent, String resolvedType,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        IBinder resultTo, String resultWho, int requestCode, int startFlags,
        ProfilerInfo profilerInfo, IActivityManager.WaitResult outResult, Configuration config,
        Bundle bOptions, boolean ignoreTargetSecurity, int userId,
        IActivityContainer iContainer, TaskRecord inTask) {

        ...

        // 根據(jù)Intent中在系統(tǒng)中找到合適的應(yīng)用的Activity,如果有多個Activity可選擇則彈出界面讓用戶選擇
        ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);

        ...

        int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType,
                aInfo, rInfo, voiceSession, voiceInteractor,
                resultTo, resultWho, requestCode, callingPid,
                callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
                options, ignoreTargetSecurity, componentSpecified, outRecord, container,
                inTask);

        ...

        return res;
    }
}

startActivityLocked方法又調(diào)用startActivityUnchecked方法:

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

    ...

    // 創(chuàng)建ActivityRecord對象
    // ActivityRecord : 在AMS中衫冻,用ActivityRecord來作為Activity的記錄者,每次啟動一個Actvity會有一個對應(yīng)
    // 的ActivityRecord對象诀紊,表示Activity的一個記錄
    ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
            intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
            requestCode, componentSpecified, voiceSession != null, mSupervisor, container,
            options, sourceRecord);

    ...

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

    ...

    // 此處Activity對應(yīng)的Task被移至前臺
    postStartActivityUncheckedProcessing(r, err, stack.mStackId, mSourceRecord, mTargetStack);
    return err;
}

startActivityUnchecked調(diào)用了ActivityStackstartActivityLocked方法和ActivityStackSupervisorresumeFocusedStackTopActivityLocked方法:

private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {

    ...

    // ActivityStack的startActivityLocked方法        
    mTargetStack.startActivityLocked(mStartActivity, newTask, mKeepCurTransition, mOptions);

    if (mDoResume) {
        final ActivityRecord topTaskActivity = mStartActivity.task.topRunningActivityLocked();
        if (!mTargetStack.isFocusable()
                || (topTaskActivity != null && topTaskActivity.mTaskOverlay
                && mStartActivity != topTaskActivity)) {
            // If the activity is not focusable, we can't resume it, but still would like to
            // make sure it becomes visible as it starts (this will also trigger entry
            // animation). An example of this are PIP activities.
            // Also, we don't want to resume activities in a task that currently has an overlay
            // as the starting activity just needs to be in the visible paused state until the
            // over is removed.
        } else {
            // ActivityStackSupervisor的resumeFocusedStackTopActivityLocked方法
            mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,mOptions);
        }

        ...
    }

    ...

}

ActivityStackSupervisor

ActivityStackSupervisorresumeFocusedStackTopActivityLocked方法如下:

boolean resumeFocusedStackTopActivityLocked(
        ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
    if (targetStack != null && isFocusedStack(targetStack)) {
        // 待啟動Activity對應(yīng)的Task為前臺棧時,調(diào)用該Task對應(yīng)ActivityStack的resumeTopActivityUncheckedLocked方法
        return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
    }
    final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
    if (r == null || r.state != RESUMED) {
        // 否則只是調(diào)用此時前臺棧的resumeTopActivityUncheckedLocked方法
        mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
    }
    return false;
}

ActivityStack

下面進入ActivityStackresumeTopActivityUncheckedLocked方法:

boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {

    ...

    result = resumeTopActivityInnerLocked(prev, options);

    ...

    return result;
}

緊接著又調(diào)用了resumeTopActivityInnerLocked方法:

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {

    ...

    // mResumedActivity指向上一次啟動的Activity
    if (mResumedActivity != null) {

        ...

        // 讓上一次的Activity進入pause狀態(tài)
        pausing |= startPausingLocked(userLeaving, false, next, dontWaitForPause);
    }

    if (pausing) {
        ...
        if (next.app != null && next.app.thread != null) {
            // 如果Activity所在App已經(jīng)啟動隅俘,則更新Activity所在進程優(yōu)先級邻奠,防止被kill
            mService.updateLruProcessLocked(next.app, true, null);
        }
        ...
    } 

    ...

    if (next.app != null && next.app.thread != null) {
        ...
        if (next.newIntents != null) {
            // 如果Intent不為空笤喳,則調(diào)用NewIntent傳入Intent參數(shù)
            next.app.thread.scheduleNewIntent(
                next.newIntents, next.appToken, false /* andPause */);
            ...
        }

        ...

        // Activity已經(jīng)啟動,重新進入前臺
        next.app.thread.scheduleResumeActivity(next.appToken, next.app.repProcState,
            mService.isNextTransitionForward(), resumeAnimOptions);
        ...

    } else {
        ...
        // 創(chuàng)建進程碌宴,啟動Activity,或者已經(jīng)啟動App杀狡,啟動Activity
        mStackSupervisor.startSpecificActivityLocked(next, true, true);
    }
    ...
    return true;
}

resumeTopActivityInnerLocked方法又調(diào)用了ActivityStackSupervisorstartSpecificActivityLocked方法:

void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
    // Is this activity's application already running?
    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);
            }
            // 目標(biāo)Activity所在APP已啟動
            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.
    }

    // 目標(biāo)Activity所在APP未啟動,通過zygote創(chuàng)建應(yīng)用進程
    mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
            "activity", r.intent.getComponent(), false, false, true);
}

startSpecificActivityLocked方法調(diào)用了realStartActivityLocked方法:

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

    ...

    // 目標(biāo)Activity所在APP已啟動唧喉,通過此方法啟動目標(biāo)Activity
    app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
        System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
        new Configuration(task.mOverrideConfig), r.compat, r.launchedFromPackage,
        task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
        newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);

    ...

}

上面這段代碼中捣卤,其中app.thread的類型是IApplicationThread忍抽,IApplicationThread的聲明如下:

public interface IApplicationThread extends IInterface {...}

IApplicationThread繼承了IInterface八孝,所以它是一個Binder類型的接口,IApplicationThread內(nèi)部包含了大量啟動鸠项、停止Activity的接口干跛,此外還包含啟動和停止服務(wù)的接口。
IApplicationThread的實現(xiàn)者就是ActivityThread的內(nèi)部類ApplicationThread祟绊,相關(guān)類的繼承和實現(xiàn)關(guān)系如下所示:

private class ApplicationThread extends ApplicationThreadNative { ... }
public abstract class ApplicationThreadNative extends Binder implements IApplicationThread { ... }

說了這么多楼入,分析下來不僅累,還容易被繞暈牧抽,畫張流程圖總結(jié)下:


流程圖

ApplicationThread

繞了一圈嘉熊,Activity的啟動過程還是回到了ApplicationThread中,ApplicationThread通過scheduleLaunchActivity方法啟動Activity扬舒,源碼如下:

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;
    r.ident = ident;
    r.intent = intent;
    r.referrer = referrer;
    r.voiceInteractor = voiceInteractor;
    r.activityInfo = info;
    r.compatInfo = compatInfo;
    r.state = state;
    r.persistentState = persistentState;

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

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

    r.profilerInfo = profilerInfo;

    r.overrideConfig = overrideConfig;
    updatePendingConfiguration(curConfig);

    sendMessage(H.LAUNCH_ACTIVITY, r);
}

其主要實現(xiàn)就是發(fā)送一個啟動消息交由Handler處理阐肤,這個Handler有個特殊的名字叫H(是不是很萌的名字),sendMessage的實現(xiàn)如下:

private void sendMessage(int what, Object obj, int arg1, int arg2, int seq) {
    if (DEBUG_MESSAGES) Slog.v(
            TAG, "SCHEDULE " + mH.codeToString(what) + " arg1=" + arg1 + " arg2=" + arg2 +
                    "seq= " + seq);
    Message msg = Message.obtain();
    msg.what = what;
    SomeArgs args = SomeArgs.obtain();
    args.arg1 = obj;
    args.argi1 = arg1;
    args.argi2 = arg2;
    args.argi3 = seq;
    msg.obj = args;
    mH.sendMessage(msg);
}

H對Activity啟動的消息進行處理:

case LAUNCH_ACTIVITY: {
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;

    r.packageInfo = getPackageInfoNoCheck(
            r.activityInfo.applicationInfo, r.compatInfo);
    handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} 
break;

ActivityThread

從上面代碼可以看出讲坎,Activity的啟動過程又轉(zhuǎn)到ActivityThreadhandleLaunchActivity方法中孕惜,其源碼如下:

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
    ...

    // 此方法中完成Activity生命周期的onCreate和onStart方法
    Activity a = performLaunchActivity(r, customIntent);

    if (a != null) {
        r.createdConfig = new Configuration(mConfiguration);
        reportSizeConfigurations(r);
        Bundle oldState = r.state;
        // 此方法中完成Activity生命周期的onResume方法
        handleResumeActivity(r.token, false, r.isForward,
                !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);

        ...
    }

    ...
}

上述代碼中的performLaunchActivity方法最終完成了Activity對象的創(chuàng)建和啟動過程,performLaunchActivity這個方法主要完成了以下幾件事:

摘自Android開發(fā)藝術(shù)探索

  1. 從ActivityClientRecord中獲取待啟動的Activity的組件信息
ActivityInfo aInfo = r.activityInfo;
if (r.packageInfo == null) {
    r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
            Context.CONTEXT_INCLUDE_CODE);
}

// ComponentName用來定義一個應(yīng)用程序組件晨炕,例如Activity,Service,BroadcastReceiver,ContentProvider
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);
}

  1. 通過Instrumentation的newActivity方法使用類加載器創(chuàng)建Activity對象
Activity activity = null;
try {
    java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
    // 通過類加載器來創(chuàng)建Activity對象
    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);
    }
}

  1. 通過LoadedApk的makeApplication方法來創(chuàng)建Application對象
public Application makeApplication(boolean forceDefaultAppClass,
        Instrumentation instrumentation) {
    // 先判斷Application是否為空衫画,如果Application被創(chuàng)建過,就不會再重復(fù)創(chuàng)建瓮栗,一個應(yīng)用只有一個Application對象
    if (mApplication != null) {
        return mApplication;
    }

    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");

    Application app = null;

    String appClass = mApplicationInfo.className;
    if (forceDefaultAppClass || (appClass == null)) {
        appClass = "android.app.Application";
    }

    try {
        java.lang.ClassLoader cl = getClassLoader();
        if (!mPackageName.equals("android")) {
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                    "initializeJavaContextClassLoader");
            initializeJavaContextClassLoader();
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        }
        ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
        // 通過類加載器創(chuàng)建Application對象
        app = mActivityThread.mInstrumentation.newApplication(
                cl, appClass, appContext);
        appContext.setOuterContext(app);
    } catch (Exception e) {
        if (!mActivityThread.mInstrumentation.onException(app, e)) {
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            throw new RuntimeException(
                "Unable to instantiate application " + appClass
                + ": " + e.toString(), e);
        }
    }
    mActivityThread.mAllApplications.add(app);
    mApplication = app;

    if (instrumentation != null) {
        try {
            // 調(diào)用Application的onCreate方法
            instrumentation.callApplicationOnCreate(app);
        } catch (Exception e) {
            if (!instrumentation.onException(app, e)) {
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                throw new RuntimeException(
                    "Unable to create application " + app.getClass().getName()
                    + ": " + e.toString(), e);
            }
        }
    }

    ...

    return app;
}

  1. 創(chuàng)建ContextImpl對象削罩,并通過Activity的attach方法來完成一些重要數(shù)據(jù)的初始化
Context appContext = createBaseContextForActivity(r, activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
if (r.overrideConfig != null) {
    config.updateFrom(r.overrideConfig);
}
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
        + r.activityInfo.name + " with config " + config);
Window window = null;
if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
    window = r.mPendingRemoveWindow;
    r.mPendingRemoveWindow = null;
    r.mPendingRemoveWindowManager = null;
}
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);

ContextImpl是一個很重要的數(shù)據(jù)結(jié)構(gòu),很明顯是Context的具體實現(xiàn)费奸,Context中大部分邏輯都是由ContextImpl實現(xiàn)的弥激。ContextImpl通過Activity的attach方法來和Activity建立關(guān)聯(lián),同時在attach方法中還會完成Window的創(chuàng)建并建立自己和Window的關(guān)聯(lián)货邓,Window接收到外部事件輸入后將事件傳遞給Activity秆撮。

  1. 調(diào)用Activity的onCreate方法
mInstrumentation.callActivityOnCreate(activity, r.state);

上述代碼中調(diào)用Activity的onCreate方法,意味著Activity已經(jīng)完成了整個啟動過程换况。此外還調(diào)用了Activity的onStart职辨,OnRestoreInstanceState方法:

activity.performStart();
...
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);

總結(jié)

至此盗蟆,整個Activity的啟動流程已經(jīng)分析完了

  • 啟動過程中涉及到的類的作用分別是什么,我們此次并沒有深入分析
  • 可以看出舒裤,Activity啟動最后涉及到Handler消息循環(huán)機制
  • Activity啟動過程中AMS的地位顯著喳资,但是進程間通信的具體本質(zhì)我也沒有分析,下一步可以分析下Android IPC機制
  • Android從開機到點擊Icon打開APP的過程中涉及到Launcher(它其實也是一個android應(yīng)用程序)的啟動以及APP進程的創(chuàng)建腾供,我們此處沒有提及仆邓。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市伴鳖,隨后出現(xiàn)的幾起案子节值,更是在濱河造成了極大的恐慌,老刑警劉巖榜聂,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件搞疗,死亡現(xiàn)場離奇詭異,居然都是意外死亡须肆,警方通過查閱死者的電腦和手機匿乃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來豌汇,“玉大人幢炸,你說我怎么就攤上這事【芗” “怎么了宛徊?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長柜思。 經(jīng)常有香客問我岩调,道長,這世上最難降的妖魔是什么赡盘? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任号枕,我火速辦了婚禮,結(jié)果婚禮上陨享,老公的妹妹穿的比我還像新娘葱淳。我一直安慰自己,他們只是感情好抛姑,可當(dāng)我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布赞厕。 她就那樣靜靜地躺著,像睡著了一般定硝。 火紅的嫁衣襯著肌膚如雪皿桑。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天,我揣著相機與錄音诲侮,去河邊找鬼镀虐。 笑死,一個胖子當(dāng)著我的面吹牛沟绪,可吹牛的內(nèi)容都是我干的刮便。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼绽慈,長吁一口氣:“原來是場噩夢啊……” “哼恨旱!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起坝疼,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤搜贤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后裙士,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體入客,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年腿椎,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片夭咬。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡啃炸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出卓舵,到底是詐尸還是另有隱情南用,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布掏湾,位于F島的核電站裹虫,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏融击。R本人自食惡果不足惜筑公,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望尊浪。 院中可真熱鬧匣屡,春花似錦、人聲如沸拇涤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鹅士。三九已至券躁,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背也拜。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工旭贬, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人搪泳。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓稀轨,卻偏偏與公主長得像,于是被迫代替她去往敵國和親岸军。 傳聞我的和親對象是個殘疾皇子奋刽,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,713評論 2 354

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