天天看點

用戶端startActivity流程走向

  • 一個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啟動。