-
一个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启动。