- 一個APP往往由許多的Activity組成,這些Activity之間肯定會發生界面跳轉,這個時候我們就需要用startActivity這個方法,傳遞一些參數;或者使用startActivityForResult可以指定傳回的requestCode。requestCode在目前Activity的onActivityResult方法中用來判斷是不是我們跳轉的Activity傳回。
- 這裡需要注意的是,對于啟動模式是SingleTask的Activity,執行startActivityForResult以後是直接傳回,不會走到onActivityResult中。
- 下面看一下它具體是怎麼走的,core/java/android/app/Activity.java#startActivity:
}@Override public void startActivity(Intent intent, @Nullable Bundle options) { if (options != null) { startActivityForResult(intent, -1, options); } else { // Note we want to go through this call for compatibility with // applications that may have overridden the method. startActivityForResult(intent, -1); }
- 通過上述代碼,我們不管調用的是startActivity還是startActivityForResult,最後都是走進startActivityForResult裡面。
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode, @Nullable Bundle options) { if (mParent == null) { options = transferSpringboardActivityOptions(options); Instrumentation.ActivityResult ar = //具體執行啟動Activity任務 mInstrumentation.execStartActivity( this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options); ----- } }
具體執行的就是execStartActivity這個方法,看一下實作:
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, String target,
Intent intent, int requestCode, Bundle options)
看一下參數,who:目前界面句柄;contextThread:用來和AMS互動的,是我們在建立第一個Acitvity時候通過ActivityThread#performLaunchActivity中通過Activity.attach方法傳進來的;intent:需要跳轉的Activity資訊:要跳轉的Activity名稱,傳遞的資料等;Bundle可選,要傳遞的資料也可以填寫在這裡。重點看一下這個方法裡面的這句話:
int result = ActivityManager.getService()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
在這裡我們走到了ActivityManagerService(AMS)中去執行:
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實作:
return mActivityStartController.obtainStarter(intent, "startActivityAsUser")
.setCaller(caller)
.setCallingPackage(callingPackage)
.setResolvedType(resolvedType)
.setResultTo(resultTo)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.setStartFlags(startFlags)
.setProfilerInfo(profilerInfo)
.setActivityOptions(bOptions)
.setMayWait(userId)
.execute();
services/core/java/com/android/am/ActivityStartController.java#obtainStarter的實作就一句話:
ActivityStarter obtainStarter(Intent intent, String reason) {
return mFactory.obtain().setIntent(intent).setReason(reason);
}
ActivityManagerService建立的時候,會做很多初始化動作,包括初始化ActivityStartController,在ActivityStartController的構造函數中直接調用ActivityStarter#DefaultFactory類,生成我們所需要的mFactory。最終通過obtain方法生成ActivityStarter句柄,并通過ActivityStarter#execute()執行。
int execute() {
try {
// TODO(b/64750076): Look into passing request directly to these methods to allow
// for transactional diffs and preprocessing.
if (mRequest.mayWait) {
return startActivityMayWait(mRequest.caller, mRequest.callingUid,
----
}
}
}
因為mRequest.mayWait為true,是以主要按照下面這個流程來實作:startActivityMayWait --> startActivity—>startActivityUnchecked,這個方法内容比較複雜,5.0以前是寫在ActivityStackSupervisor.java中,5.0以後放在了ActivityStarter.java這個新檔案中。
講到這裡就不得不提一句配置在AndroidManifest.xml中的launchMode。舉一個比較常見的場景就是A界面跳轉到B界面。5.0以前會檢查這個标志,如果A界面是SingleInstance或者B界面是SingleInstance或者SingleTask,跳轉方式是startActivityForResult,則會立即執行onActivityResult,且傳回結果為result_cancel。也就是說不會等到B界面傳回,onActivityResult就已經執行;5.0以後則隻會檢查通過intent添加的flag,但不管是何種啟動模式都是正常執行onActivityResult(也就是B界面傳回以後再執行)。且根據flag标志,如果是singleTask,則檢查該Activity是否存在執行個體,如果存在則從目前Activity往上清除至棧頂。否則就作為一個新界面跳轉。較長的描述可以參考:http://www.jianshu.com/p/2a9fcf3c11e4
還是回到startActivityUnchecked這個方法,先簡單描述一下主要實作功能:
1.setInitialState:設定初始狀态,計算出launchFlags.判斷是否為需要傳回結果(startActivityForResult啟動),如果是且launchFlags為singleTask,則立即傳回結果RESULT_CANCELED.具體在sendNewTaskResultRequestIfNeeded()方法中執行。和startActivity同樣,銷毀其上所有Activity.如果上一個界面也為singleTask,則調用onNewIntent.
2.computeLaunchingTaskFlags:繼續計算啟動标志launchFlags。如果是singleInstance或者singletask,則檢查指定的task是不是同一個,如果不是則抛出異常;否則就檢查task是否為空,為空則直接添加;如果task不為空則顯示在前台,不需要再建立task
3.computeSourceStack:計算所需要的stack
4.getReusableIntentActivity:擷取複用的task不是activity,函數名稱有歧義。
5.如果可以複用,則清除其上的所有Activity至棧頂。調用TaskRecord.java中的performClearTaskForReuseLocked方法清除(如果找不到這個activity,則建立);
6.檢查是否為topActivity(這個activity存在),如果啟動模式是singleTask或者singleInsance,則執行deliverNewIntent,發送onNewIntent給這個界面。
7.setTargetStackAndMoveToFrontIfNeeded:如果在背景就需要顯示在前台界面。
8.mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,mOptions): 添加界面Window
9.mSupervisor.resumeFocusedStackTopActivityLocked:啟動Activity
我們走進ActivityStackSupervisor.java#resumeFocusedStackTopActivityLocked看一下流程執行:
1.targetStack.resumeTopActivityUncheckedLocked
2.ActivityStack.java中:resumeTopActivityInnerLocked
3.mStackSupervisor.startSpecificActivityLocked
4.走進ActivityStackSupervisor.java#startSpecificActivityLocked,做兩件事:
(1)調用realStartActivityLocked,然後執行啟動走onCreate和onResume;
(2)調用mService.startProcessLocked建立AMS通訊,最後調用Process.start-->zygoteProcess.start-->openZygoteSocketIfNeeded,通過ZygoteState.connect建立通訊,連接配接Zygote程序。
至此完成 Activity啟動。