關於Activity的原始碼分析拖延了太久的時間,由於最近工作繁忙,加上Activity啟動原始碼非常複雜,涉及的內容很多,所以花費了很長是時間才來寫這篇原始碼分析,希望這篇分析能讓我們很容易的理解Activity的啟動流程,能解決我們在使用Activity過程中遇到的問題,這樣就達到了我們對於原始碼分析的目的了。下一篇我們介紹Activity的finish過程。
Activity啟動模式簡介:
我們知道Activity啟動模式有四種,每一種都有不同的操作,直接影響我們App的設計,為了幫助我們理解原始碼,我們先分析一下這四種模式。這四種模式包括:standard, singleTop, singleTask 和 singleInstance。
(下面內容來自:Activity啟動模式圖文詳解:standard, singleTop, singleTask 以及 singleInstance)
-
standard:標準模式,也是預設模式。這種模式是每次你呼叫startActivity時都會建立一個Activity例項,不管你之前有沒有建立過。
-
singleTop:從名字可以分析出是頂部單例,也就是如果你要啟動的Activity在任務棧的頂部,則不會在建立新的Activity例項,而是呼叫Activity的onNewIntent方法,如果你要啟動的Activity不存在或者存在但是不在任務棧的棧頂,那麼也會建立新的Activity例項並且放置到棧頂位置。因此如果你需要處理Intent中的引數,那麼需要在onCreate方法和onNewIntent方法中都要處理。
-
singleTask:從名字看是單例模式,這個單例不是棧單例,而是系統單例,也就是如果系統中存在了該Activity,那麼在呼叫startActivity時並不會重新建立一個Activity,而是將持有這個Activity的任務移動到頂部位置,並且呼叫onNewIntent方法,同時在這個棧中的該Activity上面的Activity都會被彈出棧並且被銷燬,如果系統中不存在則會建立新的Activity,並且將這個Activity放置到一個新的任務棧中的底部(root)位置。
但是,同一個應用中,我們正常使用中同一個應用中的Activity啟動卻不是這樣,啟動的具有該屬性的Activity會被放到棧的頂部,而不是放到root(底部)位置,如果需要像上面描述一樣放到root位置,那麼需要在AndroidManifest檔案中配置Activity時新增taskAffinity屬性,例如:
<activity android:name=".SingleTaskActivity" android:label="singleTask launchMode" android:launchMode="singleTask" android:taskAffinity=""> 複製程式碼
在不同的應用啟動Activity,如果兩個應用啟動具有該屬性的Activity就會建立一個新的任務,並且將該Activity放置到該任務的底部位置。除非用該屬性的Activity所在的應用已經存在了,新建立該屬性Activity後會將其放置到頂部位置。如果在其他的任務中存在了該屬性的Activity,整個任務都會被移到頂部位置,並且該Activity上面的所有Activity都會被銷燬,使用者需要按back鍵遍歷棧中的Activity才能回到呼叫者。
-
singleInstance:單例模式,這個模式和singleTask很相似,不同的是:持有這個Activity的任務只有一個Activity,即這個單例本身。如果這個Activity啟動另一個Activity的時候會自動建立一個任務棧,並且將新啟動的Activity放到該新建立的任務棧中。不過結果很怪異,當具有該模式的Activity啟動另一個Activity或者另一個Activity啟動具有該模式的Activity時本來需要建立一個新的任務,但是任務管理中只顯示了一個(最後被移到頂部的那個),導致後臺只顯示一個,我們不能切換到之前的任務中。如果想切換唯一辦法就是回到Launcher重新點選應用,但是顯示另個一任務後,第一個任務就會被隱藏了。也就是切換後還是隻能顯示一個任務。如果想要解決仍然需要設定taskAffinity屬性,例如:
<activity android:name=".SingleTaskActivity" android:label="singleTask launchMode" android:launchMode="singleTask" android:taskAffinity=""> 複製程式碼
這樣就正常了,這種模式很少使用,除非想Launcher這種只有一個Activity,或者100%確定只有一個Activity。
Activity原始碼解析
要了解Activity啟動的過程不僅要知道程式碼流程,也要知道設計流程,我們先看程式碼流程,分析完成後我們再重新看一下設計流程,來幫助我們記憶原始碼流程。因為篇幅比較長,我們下面分為兩個部分分析。
第一部分:
Step1.startActivityForResult:
Activity的啟動一般有了兩種方式,一種是需要返回結果的,一種是不需要返回結果的。這裡的函式和我們上面時序圖中的不一樣,其實最終呼叫的方法是這個,另外還有幾個引數不同的方法,其實是一樣的,我們看最終呼叫程式碼:
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
if (mParent == null) {
...
// Instrumentation是用來監控程式與系統之間的互動操作的,mMainThread的型別為ActivityThread,
// 是用來描述應用程式程式的,系統每當啟動一個應用程式程式時,都會在它裡面載入一個ActivityThread
// 類實體,並且這個類實體會儲存在每一個在該程式中啟動的Activity元件的父類Activity的成員變數
// mMainThread中。ActivityThread的成員函式getApplicationThread用來獲取它內部一個型別為
// ApplicationThread物件作為引數傳遞給變數mInstrumentation的成員函式execStartActivity,
// 以便將它傳遞給AMS,這樣就可以通過ApplicationThread與Activity交流了。Activity的成員變數
// mToken的型別為IBinder,它是Binder代理物件,指向AMS中一個型別為ActivityRecord物件,用來維護
// 對應的Activity元件的執行狀態以及資訊。此處傳入也是為了傳遞給AMS,這樣AMS就可以得到Activity的
// 詳細資訊了。
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());
}
...
} else {
...
}
}
複製程式碼
直接啟動時引數requestCode為-1,這裡執行呼叫Instrumentation.execStartActivity方法,後面執行ActivityThread.sendActivityResult返回結果,這個方法我們後面會分析,這裡不再分析,我們先看啟動的方法:
Step2.Instrumentation.execStartActivity
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
...
// 獲取AMS的代理物件AMP(ActivityManagerProxy),然後呼叫起startActivity方法,通過該方法
// 通知AMS啟動Activity
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
...
return null;
}
複製程式碼
這個方法傳入有個引數target,從上面程式碼可知傳入的是this,也就是呼叫啟動Activity方法的Activity,我們稱之為呼叫者或者源Activity。這裡主要是呼叫startActivity方法,這裡的ActivityManagerNative.getDefault()我們在前面的文字介紹過是ActivityManagerProxy。
Step3.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 {
...
// 通過AMP類內部的一個IBinder代理物件想AMS傳送一個型別為START_ACTIVITY_TRANSACTION的程式間通訊請求
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
...
return result;
}
複製程式碼
最終呼叫AMS(ActivityManagerService)的startActivity方法。
Step4.AMS.startActivity
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());
}
複製程式碼
然後呼叫startActivityAsUser方法。
Step5.AMS.startActivityAsUser
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) {
...
// mActivityStarter是Activity啟動等操作的管理者
return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
profilerInfo, null, null, bOptions, false, userId, null, null);
}
複製程式碼
呼叫ActivityStarter.startActivityMayWait方法。
Step6.ActivityStarter.startActivityMayWait
// 該函式的Wait表示對於outResult的處理上
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) {
...
// 是否指定了要啟動Activity相關的元件名,如果指定了元件名則為顯示啟動,否則為隱式啟動
boolean componentSpecified = intent.getComponent() != null;
...
// 收集Intent中的資訊
...
synchronized (mService) {
...
final ActivityRecord[] outRecord = new ActivityRecord[1];
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;
}
}
複製程式碼
這裡主要是收集Intent的內容,進行判斷整理,然後呼叫startActivityLocked方法。
Step7.startActivityLocked
// Locked 代表非執行緒安全的,提醒我們必須保證這些函式是執行緒安全的,(因為他們涉及不可重入資源的處理)
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;
// 獲取呼叫者程式記錄物件,每一個程式都使用一個ProcessRecord物件來描述,並且會儲存起來
ProcessRecord callerApp = null;
if (caller != null) {
// mService指向AMS,通過caller來獲取對應的ProcessRecord物件callerApp,引數caller指向
// 啟動Activity的元件所執行在的應用程式程式的一個ApplicationThread物件,因此ProcessRecord
// 物件callerApp指向了啟動者所在的應用程式程式(正在啟動的為被呼叫者)。
callerApp = mService.getRecordForAppLocked(caller);
if (callerApp != null) {// 呼叫者程式存在
callingPid = callerApp.pid;
callingUid = callerApp.info.uid;
} else {// 呼叫者被系統殺死或者意外退出
...
}
}
...
ActivityRecord sourceRecord = null;// 呼叫者Activity封裝
ActivityRecord resultRecord = null;// 需要接受返回結果的Activity物件封裝
if (resultTo != null) {// 需要返回結果
// 查詢所有棧中是否存在對應resultTo(呼叫者)的ActivityRecord
sourceRecord = mSupervisor.isInAnyStackLocked(resultTo);
if (sourceRecord != null) {
// 如果requestCode大於等於0(也就是需要返回結果的啟動Activity),
// 並且請求者的Activity沒有在等待finish佇列中,說明sourceRecord就是接受結果的Activity
if (requestCode >= 0 && !sourceRecord.finishing) {
// 將啟動者的Activity作為接受結果的Activity
resultRecord = sourceRecord;
}
}
}
final int launchFlags = intent.getFlags();
// 直接啟動Activity時requestCode為-1,因此sourceRecord為空,resultRecord為空
// 這裡對標誌位Intent.FLAG_ACTIVITY_FORWARD_RESULT進行了判斷,我們先解釋一下這個標誌位:如果A啟動了B
// 並且需要返回結果,而B需要啟動了C從C返回結果給A,那麼B需要設定Intent.FLAG_ACTIVITY_FORWARD_RESULT標誌
// 位,並且為了避免衝突B在啟動C時不需要再設定requestCode,而此時sourceRecord是B,resultRecord是A,
// 就是下面程式碼的解釋,設定該標誌後,C呼叫setResult時結果不會傳遞給B而是傳遞給A。
if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
// Transfer the result target from the source activity to the new
// one being started, including any failures.
// 這裡requestCode是B傳過來的,如果設定了上面的標籤,B就不能再設定requestCode,因此,如果
// requestCode>=0就會產生衝突,因此B不能再設定requestCode
if (requestCode >= 0) {
ActivityOptions.abort(options);
return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
}
// 如果設定了上面的標籤,最終的接受結果的Activity就是B(sourceRecord)中resultTo指向的Activity而不是B
resultRecord = sourceRecord.resultTo;
// 如果啟動者resultRecord不在棧中,賦值為空
if (resultRecord != null && !resultRecord.isInStackLocked()) {
resultRecord = null;
}
...
requestCode = sourceRecord.requestCode;// 傳遞requestCode
...
if (resultRecord != null) {// 還存在棧中,移除結果
resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode);
}
...
}
...
// 不需要返回結果直接啟動Activity時resultRecord為空
final ActivityStack resultStack = resultRecord == null ? null : resultRecord.task.stack;
if (err != START_SUCCESS) {// 失敗
if (resultRecord != null) {
// 需要返回結果的啟動Activity,呼叫Activity.onActivityResult,返回操作取消的結果
resultStack.sendActivityResultLocked(
-1, resultRecord, resultWho, requestCode, RESULT_CANCELED, null);
}
ActivityOptions.abort(options);
return err;
}
...
if (abort) {// 如果終止
if (resultRecord != null) {
// 等待返回結果的Activity,呼叫Activity.onActivityResult方法,返回取消操作的結果
resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode,
RESULT_CANCELED, null);
}
ActivityOptions.abort(options);
return START_SUCCESS;
}
// 建立一個ActivityRecord物件r來描述即將被啟動的Activity元件
ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
requestCode, componentSpecified, voiceSession != null, mSupervisor, container,
options, sourceRecord);
if (outActivity != null) {
outActivity[0] = r;
}
...
// 獲取棧
final ActivityStack stack = mSupervisor.mFocusedStack;
// 前面voiceSession傳入為空,並且沒有可恢復的Activity或者可恢復的Activity不是當前呼叫者
if (voiceSession == null && (stack.mResumedActivity == null
|| stack.mResumedActivity.info.applicationInfo.uid != callingUid)) {
// 前臺棧(stack)還沒有resume狀態的Activity時, 則檢查app切換是否允許,不允許切換則要放入等待列表
if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
realCallingPid, realCallingUid, "Activity start")) {
// 不許切換時,獲取啟動新Activity請求的描述,放到等待列表
PendingActivityLaunch pal = new PendingActivityLaunch(r,
sourceRecord, startFlags, stack, callerApp);
// 新增PendingActivityLaunch
mPendingActivityLaunches.add(pal);
ActivityOptions.abort(options);
return ActivityManager.START_SWITCHES_CANCELED;
}
}
// 允許切換
if (mService.mDidAppSwitch) {
mService.mAppSwitchesAllowedTime = 0;// 將切換時間設定為0
} else {
mService.mDidAppSwitch = true;
}
// 處理等待啟動的Activity
doPendingActivityLaunchesLocked(false);
try {
...
// 啟動目標Activity操作
err = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
true, options, inTask);
} finally {
mService.mWindowManager.continueSurfaceLayout();
}
postStartActivityUncheckedProcessing(r, err, stack.mStackId, mSourceRecord, mTargetStack);
return err;
}
複製程式碼
上面程式碼註釋比較詳細,有一點我們提一下就是FLAG_ACTIVITY_FORWARD_RESULT標籤,也就是我們在開發中遇到的一種情況,ActivityA啟動ActivityB,ActivityB啟動ActivityC,C返回結果讓A接收,我們平時不知道怎麼處理,通過上面原始碼我們看到可以設定這個標籤,就可以完成我們需要的操作。
上面我們在啟動失敗的時候回直接返回結果,中斷操作,呼叫ActivityStack.sendActivityResultLocked方法。
Step8.ActivityStack.sendActivityResultLocked
void sendActivityResultLocked(int callingUid, ActivityRecord r,
String resultWho, int requestCode, int resultCode, Intent data) {
...
if (mResumedActivity == r && r.app != null && r.app.thread != null) {
try {
...
r.app.thread.scheduleSendResult(r.appToken, list);
return;
}
...
}
...
}
複製程式碼
這裡會呼叫ApplicationThreadProxy.scheduleSendResult方法。
Step9.ApplicationThreadProxy.scheduleSendResult
public final void scheduleSendResult(IBinder token, List<ResultInfo> results)
throws RemoteException {
...
mRemote.transact(SCHEDULE_SEND_RESULT_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
}
複製程式碼
這個我們之前在上一章分析廣播的時候講過的,最終會呼叫ActivityThread.scheduleSendResult方法。
Step10.ActivityThread.scheduleSendResult
public final void scheduleSendResult(IBinder token, List<ResultInfo> results) {
...
sendMessage(H.SEND_RESULT, res);
}
複製程式碼
這裡通過Handler傳送訊息到ActivityThread.H.handleMessage中進行處理。然後呼叫handleSendResult方法
Step12.ActivityThread.handleSendResult
private void handleSendResult(ResultData res) {
...
if (r != null) {
final boolean resumed = !r.paused;
...
deliverResults(r, res.results);
if (resumed) {
r.activity.performResume();
r.activity.mTemporaryPause = false;
}
}
}
複製程式碼
這裡呼叫deliverResults方法分發結果,分發完成如果需要複用的,則呼叫複用方法,這個我們後面會介紹到。
Step13.ActivityThread.deliverResults
private void deliverResults(ActivityClientRecord r, List<ResultInfo> results) {
final int N = results.size();
for (int i = 0; i < N; i++) {
...
r.activity.dispatchActivityResult(ri.mResultWho,
ri.mRequestCode, ri.mResultCode, ri.mData);
...
}
}
複製程式碼
這裡呼叫Activity.dispatchActivityResult方法分發結果。
Step14.Activity.dispatchActivityResult
void dispatchActivityResult(String who, int requestCode,
int resultCode, Intent data) {
....
onActivityResult(requestCode, resultCode, data);
...
}
複製程式碼
這裡會呼叫onActivityResult方法,返回結果,其他的情況這裡不介紹了,自己分析一下就好了。到此結果返回就完成了,我們接著分析,再回到Step7,這個方法中有幾個傳送返回結果的呼叫,其實呼叫都是一樣的,接著我們分析下面的程式碼,呼叫doPendingActivityLaunchesLocked方法,後面還有startActivityUnchecked方法和postStartActivityUncheckedProcessing方法,其實這兩個方法也是重複呼叫,也就是doPendingActivityLaunchesLocked裡面也呼叫了這兩個方法,因此我們只分析一次就好了。我們從doPendingActivityLaunchesLocked方法開始分析。
Step16.ActivityStarter.doPendingActivityLaunchesLocked
// 啟動等待列表中的Activity,引數doResume傳遞過來是false
final void doPendingActivityLaunchesLocked(boolean doResume) {
while (!mPendingActivityLaunches.isEmpty()) {
final PendingActivityLaunch pal = mPendingActivityLaunches.remove(0);
// 如果mPendingActivityLaunches列表中沒有了並且需要複用時設定為複用,這裡是false
// (等待列表中最後一個是最後加進來的,所以需要複用時選擇最近的一個進行復用)
final boolean resume = doResume && mPendingActivityLaunches.isEmpty();
...
final int result = startActivityUnchecked(
pal.r, pal.sourceRecord, null, null, pal.startFlags, resume, null, null);
...
}
}
複製程式碼
這裡我們看到了呼叫了startActivityUnchecked方法和postStartActivityUncheckedProcessing方法,主要的處理都在startActivityUnchecked方法中,所以下面我們主要看startActivityUnchecked方法,這個方法呼叫結束啟動也就結束了。
Step17.ActivityStarter.startActivityUnchecked
/**
* 這個方法呼叫有兩個地方,一個是處理等待的Activity,一個是正常啟動Activity
*
* @param r 描述需要被啟動的Activity的物件
* @param sourceRecord 呼叫者的Activity的封裝
* @param voiceSession 等待的為空,否則不為空
* @param voiceInteractor 等待的為空,否則不為空
* @param startFlags 0
* @param doResume 是否需要複用,等待的不一定需要,直接啟動的需要複用
* @param options 等待的為空,否則不為空
* @param inTask 等待的為空,否則不為空
*
* @return
*/
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {
// 設定初始狀態
setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
voiceInteractor);
computeLaunchingTaskFlags();
computeSourceStack();
mIntent.setFlags(mLaunchFlags);
// 查詢有沒有可複用的Activity
mReusedActivity = getReusableIntentActivity();
...
// 如果有可複用的Activity
if (mReusedActivity != null) {
...
// mStartActivity是在setInitialState方法中賦值的,指向的是被啟動Activity物件封裝,
// 如果是第一次啟動那麼它的任務棧就不存在,此時先預設設定成啟動Activity的任務棧。
if (mStartActivity.task == null) {
mStartActivity.task = mReusedActivity.task;
}
...
// 這裡有三個條件,只需要滿足一個就執行if語句中的操作
// 1.需要清理能複用的Activity所在棧中該Activity上面的其他Activity,
// 2.該Activity是SingleInstance模式
// 3.該Activity是SingleTask模式
if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
|| mLaunchSingleInstance || mLaunchSingleTask) {
// 獲取要啟動Activity
final ActivityRecord top = mReusedActivity.task.performClearTaskForReuseLocked(
mStartActivity, mLaunchFlags);
if (top != null) {
...
top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
mStartActivity.launchedFromPackage);
}
}
sendPowerHintForLaunchStartIfNeeded(false /* forceSend */);
// 將可複用的Activity移到棧頂
mReusedActivity = setTargetStackAndMoveToFrontIfNeeded(mReusedActivity);
if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
resumeTargetStackIfNeeded();
return START_RETURN_INTENT_TO_CALLER;
}
setTaskFromIntentActivity(mReusedActivity);
// 如果不需要新增到任務棧,並且複用TaskRecord為空,說明沒有啟動一個新的Activity
// mAddingToTask為false表示要為目標Activity元件建立一個專屬任務,事實上函式會檢查這個專屬
// 任務是否存在,如果已存在,那麼就會將變數mAddingToTask的值設定為true,
if (!mAddingToTask && mReuseTask == null) {
// We didn't do anything... but it was needed (a.k.a., client don't use that
// intent!) And for paranoia, make sure we have correctly resumed the top activity.
resumeTargetStackIfNeeded();
// 需要啟動的Activity不需要重啟啟動,只需要將其放到棧頂即可
return START_TASK_TO_FRONT;
}
}
// 找不到對應類(Activity)
if (mStartActivity.packageName == null) {
if (mStartActivity.resultTo != null && mStartActivity.resultTo.task.stack != null) {
mStartActivity.resultTo.task.stack.sendActivityResultLocked(
-1, mStartActivity.resultTo, mStartActivity.resultWho,
mStartActivity.requestCode, RESULT_CANCELED, null);
}
ActivityOptions.abort(mOptions);
return START_CLASS_NOT_FOUND;
}
// If the activity being launched is the same as the one currently at the top, then
// we need to check if it should only be launched once.
final ActivityStack topStack = mSupervisor.mFocusedStack;
final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop);
...
if (dontStart) {// 不啟動
...
topStack.mLastPausedActivity = null;
if (mDoResume) {
mSupervisor.resumeFocusedStackTopActivityLocked();
}
...
top.deliverNewIntentLocked(
mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
...
// 需要啟動的Activity在棧頂
return START_DELIVERED_TO_TOP;
}
boolean newTask = false;// 是否會新建立一個任務
// Activity元件中有一個android:taskAffinity屬性,用來描述它的一個專屬任務,當AMS決定要將目標
// Activity執行在一個不同的任務中時,AMS就會檢查目標Activity元件的專屬任務是否已經存在,如果存
// 在,那麼AMS就會直接將目標Activity元件新增到它裡面執行,否則,就會先建立這個專屬任務,然後將目
// 標Activity元件新增到它裡面去執行
final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
? mSourceRecord.task : null;
// Should this be considered a new task?
if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
&& (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
newTask = true;
setTaskFromReuseOrCreateNewTask(taskToAffiliate);
...
} else if (mSourceRecord != null) {
...
final int result = setTaskFromSourceRecord();
...
} else if (mInTask != null) {
...
final int result = setTaskFromInTask();
...
} else {
...
setTaskToCurrentTopOrCreateNewTask();
}
...
mTargetStack.startActivityLocked(mStartActivity, newTask, mKeepCurTransition, mOptions);
if (mDoResume) {
if (!mLaunchTaskBehind) {
// TODO(b/26381750): Remove this code after verification that all the decision
// points above moved targetStack to the front which will also set the focus
// activity.
mService.setFocusedActivityLocked(mStartActivity, "startedActivity");
}
// 獲取頂部ActivityRecord
final ActivityRecord topTaskActivity = mStartActivity.task.topRunningActivityLocked();
...
// 恢復聚焦棧頂Activity
mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
mOptions);
...
} else {
// 新增啟動的Activity到最近任務
mTargetStack.addRecentActivityLocked(mStartActivity);
}
mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);
...
return START_SUCCESS;
}
複製程式碼
Activity的啟動最核心的東西就在這個方法中,所以這個方法會很複雜,裡面呼叫了很多方法,每個方法分析都會比較複雜,在這個方法最後返回成功,也就是Activity的啟動結束標誌。下面我們具體分析每一步的具體內容,讓我們徹底瞭解Activity的啟動流程。
Step18.ActivityStarter.setInitialState
private void setInitialState(ActivityRecord r, ActivityOptions options, TaskRecord inTask,
boolean doResume, int startFlags, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor) {
reset();// 初始化引數
mStartActivity = r;// 對mStartActivity賦值,也就是被啟動的Activity的物件封裝
...
// 判斷啟動模式,因為預設是standard模式,所以只需要與其他三個對比就可以了
mLaunchSingleTop = r.launchMode == LAUNCH_SINGLE_TOP;
mLaunchSingleInstance = r.launchMode == LAUNCH_SINGLE_INSTANCE;
mLaunchSingleTask = r.launchMode == LAUNCH_SINGLE_TASK;
mLaunchFlags = adjustLaunchFlagsToDocumentMode(
r, mLaunchSingleInstance, mLaunchSingleTask, mIntent.getFlags());
// 通過ActivityOptions.setLaunchTaskBehind方法被啟用,並且被啟動完成後就會被清理
mLaunchTaskBehind = r.mLaunchTaskBehind
&& !mLaunchSingleTask && !mLaunchSingleInstance
&& (mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0;
sendNewTaskResultRequestIfNeeded();
...
// We'll invoke onUserLeaving before onPause only if the launching
// activity did not explicitly state that this is an automated launch.
// 檢查變數mLaunchFlags的Intent.FLAG_ACTIVITY_NO_USER_ACTION位是否為1,如果等於1,那麼就
// 表示目標Activity元件不是由使用者手動啟動的,如果目標Activity元件是由使用者手動啟動的,那麼用來
// 啟動它的源Activity元件就會獲得一個使用者離開時間通知,由於目標Activity元件使使用者在應用程式啟
// 動器的介面上點選啟動的,即變數mLaunchFlags的Intent.FLAG_ACTIVITY_NO_USER_ACTION位等於0,
// 因此,成員變數mUserLeaving的值為true。
mSupervisor.mUserLeaving = (mLaunchFlags & FLAG_ACTIVITY_NO_USER_ACTION) == 0;
...
if (mOptions != null && mOptions.getLaunchTaskId() != -1 && mOptions.getTaskOverlay()) {
r.mTaskOverlay = true;
// 查詢所有的棧是否存在對應的TaskRecord
final TaskRecord task = mSupervisor.anyTaskForIdLocked(mOptions.getLaunchTaskId());
// 如果存在TaskRecord,那麼獲取頂部Activity的ActivityRecord
final ActivityRecord top = task != null ? task.getTopActivity() : null;
...
}
// intent的標誌值的位Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP也沒有置位,因此,變數notTop的值為null。
mNotTop = (mLaunchFlags & FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null;
...
}
複製程式碼
這個方法裡面主要是資料初始化,判斷啟動模式,獲取啟動標籤,為啟動Activity做準備。
Step19.ActivityStarter.adjustLaunchFlagsToDocumentMode
/**
* 從前面呼叫可知,launchFlags是從Intent中獲取的,是目標Activity元件啟動的標誌位,在launchFlags中,
* 只有Intent.FLAG_ACTIVITY_NEW_TASK位被標記為1,其它位都為0.
*
* @param r 被啟動Activity物件封裝
* @param launchSingleInstance 是不是SingleInstance模式
* @param launchSingleTask 是不是SingleTask模式
* @param launchFlags 啟動標記
*
* @return
*/
private int adjustLaunchFlagsToDocumentMode(ActivityRecord r, boolean launchSingleInstance,
boolean launchSingleTask, int launchFlags) {
// 如果launchFlags是FLAG_ACTIVITY_NEW_DOCUMENT模式並且啟動模式是singleInstance或者singleTask
if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 &&
(launchSingleInstance || launchSingleTask)) {
// 如果Intent中的標記為和manifest中的有衝突,則以manifest中的為主
launchFlags &=
~(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_MULTIPLE_TASK);
} else {
...
}
return launchFlags;
}
複製程式碼
這個方法主要是判斷啟動標籤,這裡有個提示,就是如果動態設定的標籤和AndroidManifest裡面配置的衝突,那麼以Manifest檔案中為準。
Step20.ActivityStarter.sendNewTaskResultRequestIfNeeded
private void sendNewTaskResultRequestIfNeeded() {
// 傳送條件:接收結果的Activity存在,並且mLaunchFlags是FLAG_ACTIVITY_NEW_TASK,並且接收結果的任務棧存在
if (mStartActivity.resultTo != null && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0
&& mStartActivity.resultTo.task.stack != null) {
...
mStartActivity.resultTo.task.stack.sendActivityResultLocked(-1, mStartActivity.resultTo,
mStartActivity.resultWho, mStartActivity.requestCode, RESULT_CANCELED, null);
...
}
}
複製程式碼
這裡又呼叫了上面第8步的過程--sendActivityResultLocked方法,這裡就不再介紹了,沒記住的可以回去看8-14步就可以了。
Step21.ActivityStack.sendActivityResultLocked
void sendActivityResultLocked(int callingUid, ActivityRecord r,
String resultWho, int requestCode, int resultCode, Intent data) {
...
// 呼叫onActivityResult
r.app.thread.scheduleSendResult(r.appToken, list);
...
}
複製程式碼
這個過程和上面9-15一樣,所以不再講解。
Step23.ActivityStackSupervisor.anyTaskForIdLocked
呼叫下面程式碼。
Step24.ActivityStackSupervisor.anyTaskForIdLocked
TaskRecord anyTaskForIdLocked(int id, boolean restoreFromRecents, int stackId) {
// 這裡的多個顯示一般是可能存在多視窗模式,每一個視窗用ActivityDisplay來表示,它包含了當前視窗存在的所
// 有棧,這裡遍歷所有顯示任務棧中,查詢有沒有對應id的任務。
int numDisplays = mActivityDisplays.size();
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
ActivityStack stack = stacks.get(stackNdx);
TaskRecord task = stack.taskForIdLocked(id);
if (task != null) {
return task;
}
}
}
// 根據任務id查詢最近任務列表中是否存在該認為
TaskRecord task = mRecentTasks.taskForIdLocked(id);
...
return task;
}
複製程式碼
這個方法主要是根據任務棧id查詢所有螢幕顯示的任務列表中是否存在該id對應的任務,如果有直接返回,如果沒有從最近任務中查詢,沒有直接返回null,如果有則呼叫restoreRecentTaskLocked方法儲存該任務。
Step25.ActivityStackSupervisor.restoreRecentTaskLocked
private boolean restoreRecentTaskLocked(TaskRecord task, int stackId) {
if (stackId == INVALID_STACK_ID) {// 無效的id,我們前面傳入的就是這個無效的id
stackId = task.getLaunchStackId();// 獲取當前任務的id
} else if (stackId == DOCKED_STACK_ID && !task.canGoInDockedStack()) {
...
} else if (stackId == FREEFORM_WORKSPACE_STACK_ID
&& mService.mUserController.shouldConfirmCredentials(task.userId)) {
...
}
// 當前任務中的棧管理不為空,說明已經儲存了該任務
if (task.stack != null) {
// Task has already been restored once. See if we need to do anything more
if (task.stack.mStackId == stackId) {// 這裡判斷任務棧是否在對的棧管理中。
// Nothing else to do since it is already restored in the right stack.
return true;
}
// 如果我們的任務不在對的棧管理中,我們需要先移除該任務,然後與正確的棧管理進行關聯。
task.stack.removeTask(task, "restoreRecentTaskLocked", REMOVE_TASK_MODE_MOVING);
}
...
stack.addTask(task, false, "restoreRecentTask");
...
return true;
}
複製程式碼
Step26.ActivityStack.removeTask
void removeTask(TaskRecord task, String reason, int mode) {
if (mode == REMOVE_TASK_MODE_DESTROYING) {// 長在被完全移除棧
mStackSupervisor.removeLockedTaskLocked(task);// 移除鎖定任務
...
}
final ActivityRecord r = mResumedActivity;
if (r != null && r.task == task) {// 存在可複用的Activity,並且是我們正要啟動的Activity
mResumedActivity = null;
}
final int taskNdx = mTaskHistory.indexOf(task);
final int topTaskNdx = mTaskHistory.size() - 1;
if (task.isOverHomeStack() && taskNdx < topTaskNdx) {
// 獲取要移除任務的下一個任務
final TaskRecord nextTask = mTaskHistory.get(taskNdx + 1);
...
}
mTaskHistory.remove(task);// 從歷史記錄移除
updateTaskMovement(task, true);
// 該任務模式為正在被移除銷燬,並且該任務中沒有已經啟動的Activity
if (mode == REMOVE_TASK_MODE_DESTROYING && task.mActivities.isEmpty()) {
...
// 這裡判斷是否從最近任務移除該任務
if (task.autoRemoveFromRecents() || isVoiceSession) {
...
}
}
// 該棧管理中的歷史任務為空,也就是全部被清理了或者沒有啟動任務
if (mTaskHistory.isEmpty()) {
...
}
task.stack = null;
}
複製程式碼
從當前棧中移除傳入的任務。
Step27.ActivityStack.addTask
void addTask(final TaskRecord task, final boolean toTop, String reason) {
final ActivityStack prevStack = preAddTask(task, reason, toTop);
task.stack = this;
if (toTop) {
insertTaskAtTop(task, null);
} else {// 直接插入到歷史任務的最頂部
mTaskHistory.add(0, task);
updateTaskMovement(task, false);
}
postAddTask(task, prevStack);
}
複製程式碼
將任務插入到棧中,這裡面有個insertTaskAtTop我們後面再講。
Step28.ActivityStater.computeLaunchingTaskFlags
這個方法主要是對於mLauncherFlags的處理,這裡就不再貼程式碼。
Step29.ActivityStater.computeSourceStack
private void computeSourceStack() {
// 當前Activity不存在了
if (mSourceRecord == null) {
mSourceStack = null;
return;
}
// 如果當前Activity沒有被finish
if (!mSourceRecord.finishing) {
mSourceStack = mSourceRecord.task.stack;
return;
}
...
// 如果當前Activity正在被finish,並且啟動模式不是啟動一個新的任務,那麼我們要新增啟動新任務的標籤。
if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0) {
Slog.w(TAG, "startActivity called from finishing " + mSourceRecord
+ "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
mNewTaskInfo = mSourceRecord.info;
mNewTaskIntent = mSourceRecord.task.intent;
}
mSourceRecord = null;
mSourceStack = null;
}
複製程式碼
這裡主要是獲取mSourceStack是否存在。
Step30.ActivityStater.getReusableIntentActivity
/**
* 決定新的Activity是否應該被插入到已經存在的任務棧中。如果不插入,返回null,
* 否則返回一個帶有新Activity加入的任務棧的ActivityRecord
*/
private ActivityRecord getReusableIntentActivity() {
// 是否放置到已經存在的任務棧中
boolean putIntoExistingTask = ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
(mLaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
|| mLaunchSingleInstance || mLaunchSingleTask;
...
ActivityRecord intentActivity = null;
if (mOptions != null && mOptions.getLaunchTaskId() != -1) {
// 根據Id獲取任務
final TaskRecord task = mSupervisor.anyTaskForIdLocked(mOptions.getLaunchTaskId());
// 如果任務存在啟動的Activity就是任務中頂部的Activity
intentActivity = task != null ? task.getTopActivity() : null;
} else if (putIntoExistingTask) {// 如果需要放到已存在任務中
if (mLaunchSingleInstance) {// SingleInstance模式下,在歷史記錄中只有一個Activity的例項,並且它一直在它獨有的任務棧中。
intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info, false);
} else if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {// 是不是分屏模式
intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info,
!mLaunchSingleTask);
} else {
intentActivity = mSupervisor.findTaskLocked(mStartActivity);
}
}
return intentActivity;
}
複製程式碼
這裡是獲取一個可複用的Activity,可能存在,也可能為null。
Step31.ActivityStackSupervisor.anyTaskForIdLocked
這裡方法和上面23一樣,所以不在講解,我們接著看36步。
Step36.ActivityStackSupervisor.findActivityLocked
// 查詢棧中是否存在與被啟動Activity相同的Activity,如果存在取第一個返回,不存在返回空
ActivityRecord findActivityLocked(Intent intent, ActivityInfo info,
boolean compareIntentFilters) {
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
final ActivityRecord ar = stacks.get(stackNdx)
.findActivityLocked(intent, info, compareIntentFilters);
if (ar != null) {
return ar;
}
}
}
return null;
}
複製程式碼
根據for迴圈來查詢對應的Activity。
Step37.ActivityStack.findActivityLocked
ActivityRecord findActivityLocked(Intent intent, ActivityInfo info,
boolean compareIntentFilters) {
...
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
...
}
return null;
}
複製程式碼
從棧頂開始,返回第一個與該要啟動的Activity相同的Activity,如果沒有則返回空
Step38.ActivityStackSupervisor.findTaskLocked
ActivityRecord findTaskLocked(ActivityRecord r) {
...
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
...
// 查詢棧中是否存在對應的Activity
stack.findTaskLocked(r, mTmpFindTaskResult);
..
}
}
if (DEBUG_TASKS && mTmpFindTaskResult.r == null) Slog.d(TAG_TASKS, "No task found");
return mTmpFindTaskResult.r;
}
複製程式碼
這裡考慮到了分屏,查詢所有螢幕上是否存在對應的Activity。
Step39.ActivityStack.findTaskLocked
這個方法沒有太複雜的東西,所以不再貼程式碼,主要根據傳入的引數查詢存在該Activity的task。
Step40.TaskRecord.performClearTaskForReuseLocked
ActivityRecord performClearTaskForReuseLocked(ActivityRecord newR, int launchFlags) {
...
final ActivityRecord result = performClearTaskLocked(newR, launchFlags);
...
}
複製程式碼
呼叫performClearTaskLocked方法:
Step41.TaskRecord.performClearTaskLocked
final ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) {
int numActivities = mActivities.size();
for (int activityNdx = numActivities - 1; activityNdx >= 0; --activityNdx) {
ActivityRecord r = mActivities.get(activityNdx);
if (r.finishing) {// 如果正在finish過濾掉
continue;
}
// 如果是要找的Activity,則finish掉所在棧中上面的所有Activity
if (r.realActivity.equals(newR.realActivity)) {// 判斷ComponentName(包名類名)
// Here it is! Now finish everything in front...
// 如果包名類名一樣,則說明就是要找的和被啟動Activity一樣的Activity,其實就是要啟動這個Activity
final ActivityRecord ret = r;
for (++activityNdx; activityNdx < numActivities; ++activityNdx) {
r = mActivities.get(activityNdx);
if (r.finishing) {
continue;
}
...
// 開始清理要啟動的Activity上面的Activity
if (stack != null && stack.finishActivityLocked(
r, Activity.RESULT_CANCELED, null, "clear-task-stack", false)) {
--activityNdx;
--numActivities;
}
}
...
}
}
return null;
}
複製程式碼
這裡主要是要清理可複用Activity棧中該Activity頂部的Activity,清理呼叫ActivityStack.finishActivityLocked方法進行清理,這個方法我們在下一章Activity的finish過程再講。
Step43.ActivityRecord.deliverNewIntentLocked
final void deliverNewIntentLocked(int callingUid, Intent intent, String referrer) {
...
// 如果正在啟動的Activity已經存在,不需要建立新的Activity,則會呼叫Activity中的onNewIntent
app.thread.scheduleNewIntent(
ar, appToken, state == ActivityState.PAUSED /* andPause */);
...
}
複製程式碼
清理完成後,該可複用Activity就會到達棧頂,此時要呼叫onNewIntent方法,呼叫過程就是上面scheduleNewIntent開始,後面的步驟和上面10-15基本一樣所以不再詳細講解,其實從廣播到Activity啟動宣告週期或者內部方法的呼叫都是一樣的過程,你只要熟悉一個方法的過程,所有方法的過程就全部都會了,所以這裡還是比較容易學習的。
Step52.ActivityStarter.setTargetStackAndMoveToFrontIfNeeded
如果可複用的Activity存在那麼就要設定並且將其移到最前面來,也就是棧頂。
private ActivityRecord setTargetStackAndMoveToFrontIfNeeded(ActivityRecord intentActivity) {
// 將要啟動的Activity所在任務所在的棧作為目標棧
mTargetStack = intentActivity.task.stack;
...
// 獲取當前焦點棧
final ActivityStack focusStack = mSupervisor.getFocusedStack();
// 獲取焦點棧中最上面正在執行的非延遲Activity
ActivityRecord curTop = (focusStack == null)
? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop);
// 這裡三個條件:
// 1.存在上面獲取的Activity,
// 2.該Activity和要啟動Activity不在同一個任務,或者該Activity不是最頂部的任務(也就是不是第一個任務)
// 3.需要移動到頂部
if (curTop != null
&& (curTop.task != intentActivity.task || curTop.task != focusStack.topTask())
&& !mAvoidMoveToFront) {
mStartActivity.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
// 源Activity不存在或者源Activity所在棧頂部Activity存在並且頂部Activity和源Activity不在同一個任務中
if (mSourceRecord == null || (mSourceStack.topActivity() != null &&
mSourceStack.topActivity().task == mSourceRecord.task)) {
...
// 是否建立新任務並且清理該任務中的其他Activity
final boolean willClearTask =
(mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
== (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
if (!willClearTask) {// 不清理
// 獲取啟動棧
final ActivityStack launchStack = getLaunchStack(
mStartActivity, mLaunchFlags, mStartActivity.task, mOptions);
// 如果啟動棧不存在,或者啟動棧不是目標棧
if (launchStack == null || launchStack == mTargetStack) {
// We only want to move to the front, if we aren't going to launch on a
// different stack. If we launch on a different stack, we will put the
// task on top there.
// 把目標棧移動到前臺
mTargetStack.moveTaskToFrontLocked(
intentActivity.task, mNoAnimation, mOptions,
mStartActivity.appTimeTracker, "bringingFoundTaskToFront");
mMovedToFront = true;// 標記
} else if (launchStack.mStackId == DOCKED_STACK_ID
|| launchStack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID) {
// 如果是分屏模式,被啟動的Activity會顯示到啟動它的Activity所在螢幕上
if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
mSupervisor.moveTaskToStackLocked(intentActivity.task.taskId,
launchStack.mStackId, ON_TOP, FORCE_FOCUS, "launchToSide",
ANIMATE);
} else {// 不是分屏模式
mTargetStack.moveTaskToFrontLocked(intentActivity.task, mNoAnimation,
mOptions, mStartActivity.appTimeTracker,
"bringToFrontInsteadOfAdjacentLaunch");
}
...
}
}
...
return intentActivity;
}
複製程式碼
這裡相對操作複雜,就是如果滿足上面三個條件,就要將目標任務移動到前臺來,這裡呼叫了兩個方法:mTargetStack.moveTaskToFrontLocked和mSupervisor.moveTaskToStackLocked。我們先看第一個:
Step53.ActivityStack.moveTaskToFrontLocked
final void moveTaskToFrontLocked(TaskRecord tr, boolean noAnimation, ActivityOptions options,
AppTimeTracker timeTracker, String reason) {
...
insertTaskAtTop(tr, null);
...
addRecentActivityLocked(top);
...
// Set focus to the top running activity of this stack.
ActivityRecord r = topRunningActivityLocked();
mService.setFocusedActivityLocked(r, reason);
...
mStackSupervisor.resumeFocusedStackTopActivityLocked();
...
}
複製程式碼
這裡有幾個操作:將任務插入到頂部,將最頂部的Activity描述物件放到最近任務的列表中,獲取頂部執行的Activity並將其設定為聚焦Activity,我們一個一個分析。
Step54.ActivityStack.insertTaskAtTop
// 插入任務到頂部
private void insertTaskAtTop(TaskRecord task, ActivityRecord newActivity) {
boolean isLastTaskOverHome = false;
// If the moving task is over home stack, transfer(轉移) its return type to next task
if (task.isOverHomeStack()) {// 當前任務不是普通應用任務
// 獲取相同使用者下當前任務的下一個任務
final TaskRecord nextTask = getNextTask(task);
if (nextTask != null) {// 存在下一個任務,
// 則將下一個任務返回任務的型別設定為插入任務的型別
nextTask.setTaskToReturnTo(task.getTaskToReturnTo());
} else {// 如果不存在,那麼當前任務就是最後一個了
isLastTaskOverHome = true;
}
}
// If this is being moved to the top by another activity or being launched from the home
// activity, set mTaskToReturnTo accordingly(相應的).
if (isOnHomeDisplay()) {// 預設螢幕
// 獲取上一個有焦點的棧管理
ActivityStack lastStack = mStackSupervisor.getLastStack();
final boolean fromHome = lastStack.isHomeStack();
if (!isHomeStack() && (fromHome || topTask() != task)) {
// If it's a last task over home - we default to keep its return to type not to
// make underlying task focused when this one will be finished.
int returnToType = isLastTaskOverHome
? task.getTaskToReturnTo() : APPLICATION_ACTIVITY_TYPE;
if (fromHome && StackId.allowTopTaskToReturnHome(mStackId)) {
returnToType = lastStack.topTask() == null
? HOME_ACTIVITY_TYPE : lastStack.topTask().taskType;
}
task.setTaskToReturnTo(returnToType);
}
} else {
task.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
}
// 從歷史任務中移除該任務
mTaskHistory.remove(task);
// Now put task at top.插入任務到頂部
int taskNdx = mTaskHistory.size();
// 判斷是否顯示
final boolean notShownWhenLocked =
(newActivity != null && (newActivity.info.flags & FLAG_SHOW_FOR_ALL_USERS) == 0)
|| (newActivity == null && task.topRunningActivityLocked() == null);
// 如果插入任務不是當前使用者的任務,並且也不進行顯示
if (!mStackSupervisor.isCurrentProfileLocked(task.userId) && notShownWhenLocked) {
// Put non-current user tasks below current user tasks.
// 這裡說明插入的任務不是當前使用者的任務,那麼從頂部向下查詢,一直找到第一不是當前使用者的任務的位置,
while (--taskNdx >= 0) {
final TaskRecord tmpTask = mTaskHistory.get(taskNdx);
if (!mStackSupervisor.isCurrentProfileLocked(tmpTask.userId)
|| tmpTask.topRunningActivityLocked() == null) {
break;
}
}
// 如果插入的任務不是當前使用者的,那麼就將該非當前使用者任務插入到當前使用者的任務下面並且在不是當前使用者
// 的任務上面,也就是如果插入任務不是當前使用者的那麼就要將該任務插入到當前使用者任務和非當前使用者任務中間
++taskNdx;
}
// 插入任務
mTaskHistory.add(taskNdx, task);
updateTaskMovement(task, true);
}
複製程式碼
這裡面主要是要考慮插入的任務是不是當前使用者的任務,如果不是要依次查詢非當前使用者任務位置,然後將其放置到非當前使用者任務的頂部位置。55步是將其新增到最近任務記錄中。56步是獲取頂部執行的Activity的描述物件。
Step57.ActivityManagerService.setFocusedActivityLocked
boolean setFocusedActivityLocked(ActivityRecord r, String reason) {
...
// 將要啟動的Activity移動到前臺
if (mStackSupervisor.moveActivityStackToFront(r, reason + " setFocusedActivity")) {
mWindowManager.setFocusedApp(r.appToken, true);
}
...
return true;
}
複製程式碼
這裡主要是通過呼叫ActivityStackSupervisor.moveActivityStackToFront方法移動焦點到新的Activity。
Step58.ActivityStackSupervisor.moveActivityStackToFront
// 將要啟動的Activity移動到前臺
boolean moveActivityStackToFront(ActivityRecord r, String reason) {
...
// 將任務移動到前臺
task.stack.moveToFront(reason, task);
return true;
}
複製程式碼
Step59.ActivityStack.moveToFront
void moveToFront(String reason, TaskRecord task) {
...
mStackSupervisor.setFocusStackUnchecked(reason, this);
...
insertTaskAtTop(task, null);
...
}
複製程式碼
將任務移動到頂部,方法講過了看上面的程式碼分析。
Step60.ActivityStackSupervisor.resumeFocusedStackTopActivityLocked
boolean resumeFocusedStackTopActivityLocked() {
return resumeFocusedStackTopActivityLocked(null, null, null);
}
複製程式碼
Step61.ActivityStackSupervisor.resumeFocusedStackTopActivityLocked
boolean resumeFocusedStackTopActivityLocked(
ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
if (targetStack != null && isFocusedStack(targetStack)) {// 如果目標棧存在並且處於聚焦狀態,直接啟動
return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}
// 如果目標棧不存在或者沒有在聚焦狀態,則從聚焦棧中取出棧頂的Activity
final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
if (r == null || r.state != RESUMED) {
mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
}
return false;
}
複製程式碼
Step62.ActivityStack.resumeTopActivityUncheckedLocked
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
...
result = resumeTopActivityInnerLocked(prev, options);
...
}
複製程式碼
最終呼叫resumeTopActivityInnerLocked方法來進行處理,這個比較複雜,我們放到第二部分分析。我們回到前面接著分析。
Step63.ActivityStackSupervisor.moveTaskToStackLocked
boolean moveTaskToStackLocked(int taskId, int stackId, boolean toTop, boolean forceFocus,
String reason, boolean animate) {
return moveTaskToStackLocked(taskId, stackId, toTop, forceFocus, reason, animate,
false /* deferResume */);
}
複製程式碼
Step64.ActivityStackSupervisor.moveTaskToStackLocked
boolean moveTaskToStackLocked(int taskId, int stackId, boolean toTop, boolean forceFocus,
String reason, boolean animate, boolean deferResume) {
// 根據id獲取Task描述物件TaskRecord
final TaskRecord task = anyTaskForIdLocked(taskId);
...
resumeFocusedStackTopActivityLocked();
...
}
複製程式碼
第一個方法我們前面已經分析過了,這裡不再提,第二個方法我們上面Step60已經分析過了。
Step65.ActivityStarter.resumeTargetStackIfNeeded
// 恢復目標棧
private void resumeTargetStackIfNeeded() {
...
mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, null, mOptions);
...
}
複製程式碼
這裡就是上面64中的方法也就是60步。
Step66.ActivityStarter.setTaskFromIntentActivity
這個方法主要是目標ActivityRecord物件中獲取task。程式碼不多,可以自己看看。
Step68.ActivityStarter.setTaskFromReuseOrCreateNewTask
private void setTaskFromReuseOrCreateNewTask(TaskRecord taskToAffiliate) {
mTargetStack = computeStackFocus(mStartActivity, true, mLaunchBounds, mLaunchFlags,
mOptions);
if (mReuseTask == null) {// 沒有可用任務
// 建立新的任務並插入棧中
final TaskRecord task = mTargetStack.createTaskRecord(
mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId),
mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
mNewTaskIntent != null ? mNewTaskIntent : mIntent,
mVoiceSession, mVoiceInteractor, !mLaunchTaskBehind /* toTop */);
mStartActivity.setTask(task, taskToAffiliate);
...
} else {
mStartActivity.setTask(mReuseTask, taskToAffiliate);
}
}
複製程式碼
如果沒有可複用的任務就需要建立新的任務,並且新增,如果有就直接新增。
Step71.ActivityStack.startActivityLocked
// 啟動Activity(Locked表示執行緒安全的)
final void startActivityLocked(ActivityRecord r, boolean newTask, boolean keepCurTransition,
ActivityOptions options) {
TaskRecord rTask = r.task;
final int taskId = rTask.taskId;
// mLaunchTaskBehind tasks get placed at the back of the task stack.
if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) {
// Last activity in task had been removed or ActivityManagerService is reusing task.
// Insert or replace.
// Might not even be in.
// task中的上一個activity已被移除,或者AMS重用該task,則將該task移到頂部
insertTaskAtTop(rTask, r);
mWindowManager.moveTaskToTop(taskId);
}
// 將目標Activity放到棧頂
task.addActivityToTop(r);
task.setFrontOfTask();
...
}
複製程式碼
這裡就是將Activity放到棧頂,然後顯示。
Step72.ActivityStack.addRecentActivityLocked
這個方法在55步分析過不再分析。
這裡是第一部分的,因此啟動過程很複雜所以時序圖很多,只能分兩部分來講,很多的程式碼沒有分析,需要的可以去忘得coding拉取程式碼來看,裡面有註釋。
第二部分:
這一部分是上面過程的中間一段過程,由於東西比較多,時序圖沒法畫了,所以提取出來單獨分析,主要是ActivityStack.resumeTopActivityInnerLocked方法。
Step1.ActivityStack.resumeTopActivityInnerLocked
/**
* 1.當找不到需要resume的Activity,則直接回到桌面;
* 2.否則,當mResumedActivity不為空,則執行startPausingLocked()暫停該activity;
* 3.然後再進入startSpecificActivityLocked環節。
*
* @param prev 源Activity物件
* @param options
*
* @return
*/
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
...
// Find the first activity that is not finishing.
// 前面我們把要啟動的Activity放置在當前Activity元件堆疊的頂端,並且它是正在等待啟動的,即它不是
// 處於結束狀態的,因此next就指向了我們將要啟動的Activity元件
final ActivityRecord next = topRunningActivityLocked();
// Remember how we'll process this pause/resume situation, and ensure
// that the state is reset however we wind up proceeding.
// 將mUserLeaving放置在userLeaving中,並且重置mUserLeaving為false,因此就可以通過userLeaving
// 判斷是否需要向源Activity元件傳送一個使用者離開的時間通知了
final boolean userLeaving = mStackSupervisor.mUserLeaving;
mStackSupervisor.mUserLeaving = false;
final TaskRecord prevTask = prev != null ? prev.task : null;
if (next == null) {// 如果要啟動的Activity為空,因為我們有要啟動的Activity,因此不走這裡
...
if (!mFullscreen && adjustFocusToNextFocusableStackLocked(returnTaskType, reason)) {
// Try to move focus to the next visible stack with a running activity if this
// stack is not covering the entire screen.
return mStackSupervisor.resumeFocusedStackTopActivityLocked(
mStackSupervisor.getFocusedStack(), prev, null);
}
...
// 暫停其他Activity
boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, dontWaitForPause);
// 我們從一個Activity啟動另一個Activity的時候,源Activity不是空,mResumedActivity指向源Activity,
// 因此mResumedActivity不為空
if (mResumedActivity != null) {
if (DEBUG_STATES) Slog.d(TAG_STATES,
"resumeTopActivityLocked: Pausing " + mResumedActivity);
// 檢測是否正在終止一個Activity元件,如果是,那麼要等到它中止完成之後再啟動Activity元件next
pausing |= startPausingLocked(userLeaving, false, next, dontWaitForPause);
}
...
// If the most recent activity was noHistory but was only stopped rather
// than stopped+finished because the device went to sleep, we need to make
// sure to finish it as we're making a new activity topmost.
if (mService.isSleepingLocked() && mLastNoHistoryActivity != null &&
!mLastNoHistoryActivity.finishing) {
...
requestFinishActivityLocked(mLastNoHistoryActivity.appToken, Activity.RESULT_CANCELED,
null, "resume-no-history", false);
...
}
...
// 呼叫onActivityResult函式
next.app.thread.scheduleSendResult(next.appToken, a);
...
next.app.thread.scheduleNewIntent(
next.newIntents, next.appToken, false /* andPause */);
...
// 觸發onResume()
next.app.thread.scheduleResumeActivity(next.appToken, next.app.repProcState,
mService.isNextTransitionForward(), resumeAnimOptions);
...
mStackSupervisor.startSpecificActivityLocked(next, true, false);
...
requestFinishActivityLocked(next.appToken, Activity.RESULT_CANCELED, null,
"resume-exception", true);
...
// 目標Activity沒有啟動會呼叫startSpecificActivityLocked來啟動Activity
mStackSupervisor.startSpecificActivityLocked(next, true, true);
}
...
return true;
}
複製程式碼
這個函式程式碼量很大,我只留下了核心的一些來分析,其他的可以對照原始碼進行分析。
Step2.ActivityStack.adjustFocusToNextFocusableStackLocked
private boolean adjustFocusToNextFocusableStackLocked(int taskToReturnTo, String reason) {
final ActivityStack stack = getNextFocusableStackLocked();// 獲取下一個有焦點的棧
final String myReason = reason + " adjustFocusToNextFocusableStack";
if (stack == null) {// 沒有能獲取焦點的棧了
return false;
}
// 獲取有焦點的頂部執行的Activity物件
final ActivityRecord top = stack.topRunningActivityLocked();
// 如果頂部stack是Launcher或者最近任務所在的stack,並且存在該Activity,並且該Activity沒有顯示
if (stack.isHomeStack() && (top == null || !top.visible)) {
// 那麼要顯示Launcher或者最近任務
return mStackSupervisor.moveHomeStackTaskToTop(taskToReturnTo, reason);
}
return mService.setFocusedActivityLocked(top, myReason);
}
複製程式碼
這裡是獲取下一個能夠獲取焦點的棧,比如最近任務或者Launcher,如果獲取不到返回false,如果存在,那麼獲取該棧的頂部Activity,如果是HomeStack也就是Launcher棧或者最近任務棧,並且頂部Activity沒有顯示或者不存在則顯示Launcher或者最近任務介面。否則設定到AMS中作為焦點Activity,這個函式我們講過了。
步驟3裡的函式我們也分析過了,這裡也不再分析,我們開始分析第四步。
Step4.ActivityStackSupervisor.pauseBackStacks
boolean pauseBackStacks(boolean userLeaving, ActivityRecord resuming, boolean dontWait) {
boolean someActivityPaused = false;
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
...
someActivityPaused |= stack.startPausingLocked(userLeaving, false, resuming,
dontWait);
...
}
}
return someActivityPaused;
}
複製程式碼
通過for迴圈暫停所有後臺棧中的Activity
Step5.ActivityStack.startPausingLocked
final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping,
ActivityRecord resuming, boolean dontWait) {
if (mPausingActivity != null) {
...
completePauseLocked(false, resuming);
...
}
複製程式碼
如果需要暫停的Activity不為空,那麼要完成暫停操作。
Step6.ActivityStack.completePauseLocked
private void completePauseLocked(boolean resumeNext, ActivityRecord resuming) {
ActivityRecord prev = mPausingActivity;
// 在前面我們將mPausingActivity指向了與源Activity元件對應的ActivityRecord物件,此處為true
if (prev != null) {
// 表示源Activity狀態已經是Paused狀態了
prev.state = ActivityState.PAUSED;
if (prev.finishing) {// 如果是正在結束
prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false);
} else if (prev.app != null) {// 程式還存在
...
if (prev.deferRelaunchUntilPaused) {
// Complete the deferred relaunch that was waiting for pause to complete.
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Re-launching after pause: " + prev);
relaunchActivityLocked(prev, prev.configChangeFlags, false,
prev.preserveWindowOnDeferredRelaunch);
}
...
}
...
}
...
}
複製程式碼
finish的過程我們下一章再分析,我們下面分析一個核心的函式relaunchActivityLocked,由於下面會涉及Activity的啟動,因此我們通過這個函式直接來分析。
Step7.ActivityStack.relaunchActivityLocked
private void relaunchActivityLocked(
ActivityRecord r, int changes, boolean andResume, boolean preserveWindow) {
...
r.app.thread.scheduleRelaunchActivity(r.appToken, results, newIntents, changes,
!andResume, new Configuration(mService.mConfiguration),
new Configuration(r.task.mOverrideConfig), preserveWindow);
...
}
複製程式碼
看到什麼程式碼應該很熟悉了,呼叫ApplicationThreadProxy.scheduleRelaunchActivity方法然後通過Binder呼叫ApplicationThread.scheduleRelaunchActivity函式。我這裡的圖就省略了中間的過程。但是要知道這個過程。
Step8.ApplicationThread.scheduleRelaunchActivity
public final void scheduleRelaunchActivity(IBinder token,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
int configChanges, boolean notResumed, Configuration config,
Configuration overrideConfig, boolean preserveWindow) {
requestRelaunchActivity(token, pendingResults, pendingNewIntents,
configChanges, notResumed, config, overrideConfig, true, preserveWindow);
}
複製程式碼
Step9.ActivityThread.requestRelaunchActivity
public final void requestRelaunchActivity(IBinder token,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
int configChanges, boolean notResumed, Configuration config,
Configuration overrideConfig, boolean fromServer, boolean preserveWindow) {
...
sendMessage(H.RELAUNCH_ACTIVITY, target);
...
}
複製程式碼
這個過程應該很熟悉了,所以這裡不再多解釋。後面就直接分析過程了。這裡回到ActivityThread.H的handleMessage方法中,然後呼叫ActivityThread.handleRelaunchActivity方法。
Step10.ActivityThread.handleRelaunchActivity
private void handleRelaunchActivity(ActivityClientRecord tmp) {
...
// Need to ensure state is saved.
if (!r.paused) {
performPauseActivity(r.token, false, r.isPreHoneycomb(), "handleRelaunchActivity");
}
if (r.state == null && !r.stopped && !r.isPreHoneycomb()) {
callCallActivityOnSaveInstanceState(r);
}
handleDestroyActivity(r.token, false, configChanges, true);
...
handleLaunchActivity(r, currentIntent, "handleRelaunchActivity");
...
}
複製程式碼
這裡performPauseActivity會根據12-17步一直執行到Activity.onPause方法。 callCallActivityOnSaveInstanceState方法會執行18-21步驟最終執行Activity.onSaveInstanceState方法。 handleDestroyActivity方法會執行到Activity.onDestroy方法。 這些過程都很簡單跟著程式碼走一下就都知道了,過程基本相同。
Step23.ActivityThread.handleLaunchActivity
// 啟動Activity
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
...
// Make sure we are running with the most recent config.
// 最終回撥目標Activity的onConfigurationChanged()
handleConfigurationChanged(null, null);
...
// 首先呼叫performLaunchActivity方法將目標Activity元件啟動起來,最終呼叫目標Activity的onCreate方法
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
...
// 最終回撥目標Activity的onStart,onResume.
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
if (!r.activity.mFinished && r.startsNotResumed) {
...
performPauseActivityIfNeeded(r, reason);
...
} else {
...
}
}
複製程式碼
上面程式碼中handleConfigurationChanged方法最終會呼叫Activity.onConfigurationChanged方法。handleResumeActivity方法最終會呼叫Activity.onResume方法。最主要還是看performLaunchActivity方法。
Step28.ActivityThread.performLaunchActivity
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
Activity activity = null;
try {
// 將目標Activity的類檔案載入到記憶體中,並建立一個例項。由於所有Activity元件都是從Activity類
// 繼承下來的,因此,我們就可以將前面建立的Activity元件儲存在Activity物件activity中
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
...
try {
// 建立Application物件
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
if (activity != null) {
...
// 使用ContextImpl物件appContext和ActivityClientRecord物件r來初始化Activity物件activity
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);
...
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme);
}
activity.mCalled = false;
// 呼叫成員變數mInstrumentation的callActivityOnCreate方法將Activity物件activity啟動起來,
// 會呼叫Activity的onCreate方法
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;
}
if (!r.activity.mFinished) {
if (r.isPersistable()) {
if (r.state != null || r.persistentState != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
r.persistentState);
}
} else if (r.state != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
}
}
...
}
...
return activity;
}
複製程式碼
這個啟動過程: 通過29步載入Activity, 然後通過31步建立Application, 在35步呼叫Application的onCreate方法, 37步呼叫Activity的attach方法, 38步設定主題, 39步呼叫Activity的onCreate方法, 42步呼叫Activity的onStart方法, 45步呼叫Activity的onRestoreInstanceState方法, 然後回到ActivityThread.handleLaunchActivity方法執行handleResumeActivity方法,也就是48步以後; 在呼叫onResume函式之前可能會先呼叫onNewIntent方法和onActivityResult方法,這樣一來onResume函式之前的一個流程基本就出來了,由於程式碼比較簡單,這裡不再貼程式碼,自己跟著這個流程自己看看就知道了。
再看65步到67步,這個是從外面呼叫onActivityResult、onNewIntent和onResume方法的和第一部分的8-15步一樣,可以參考前面的就好了。
最後68-70步其實還是會執行到handleLaunchActivity方法上來,所以這裡就不再分析。
從整篇文章看,Activity的啟動流程是非常複雜,可以說在四大元件中是最複雜的,但是裡面很多過程是相同的,比如生命週期的每個方法的呼叫過程基本是一樣的,因此看書谷歌工程師設計的巧妙,這樣也有助於我們對於原始碼的學習,減少了我們對於原始碼的分析過程,部落格寫了很多,但是對於整個過程來說還是很多地方沒有分析,想了解完整的過程的可以下載我的程式碼,裡面有很全面的註釋,然後自己對著上面的時序圖來進行分析,過幾遍也就熟悉了,我寫這片部落格也用了很長的時間,主要是中間總是有事,寫寫停停,時序圖更改了好幾次。中間也有一些問題,不過跟著原始碼走還是都能找到的。
程式碼地址:
直接拉取匯入開發工具(Intellij idea或者Android studio)
注
Android開發群:192508518
微信公眾賬號:Code-MX
注:本文原創,轉載請註明出處,多謝。