Android中的task作用和Activity启动模式以及各种启动Flag的含义
在分析点击android桌面app图标启动应用程序的过程这篇文章中,第三步和第十二步简单提到了启动activity的启动标识FLAG_ACTIVITY_NEW_TASK以及task的概念.
这里就来讲解一下task,activity启动模式,启动标识相关知识.
参考https://developer.android.com/guide/components/tasks-and-back-stack.html#ManagingTasks.
task(任务)的作用是确保Activity启动和退出的顺序.activity必须在一个任务中启动,一个任务中可以有个多个activity.当然系统中可以有多个任务.这些任务中的activity都是有序的.任务是栈的结构,所以activity启动和退出遵循"后进先出".
既然activity必须在一个任务中启动,那么决定activity在哪个任务中启动(这里有可能是在现有的任务中也有可能创建一个新任务)则由activity启动模式和启动标识两者共同决定.
activity启动模式是在清单配置文件中声明Activity时使用<activity>
元素的launchMode
属性指定 .这里可以看作是该activity本身自己希望在哪个任务中启动
启动标识是指调用startActivity()
时,可以在Intent
中加入一个标志,用于声明新 目标Activity 在哪个任务中启动.这里可以看作是调用者希望目标activity如何启动.
在分析点击android桌面app图标启动应用程序的过程一文中在launcher应用程序(调用者)在启动目标actvitity的intent中添加了FLAG_ACTIVITY_NEW_TASK标识,是希望创建一个新的任务,在该新的任务中启动该activity.此时目标activity的launchMode值是
"standard"
(默认模式)所以:
①
final int startActivityUncheckedLocked(ActivityRecord r, ActivityRecord sourceRecord, int startFlags, boolean doResume, Bundle options) { int launchFlags = intent.getFlags(); ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null; if (sourceRecord == null) { // This activity is not being started from another... in this // case we -always- start a new task. if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) { .... } } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { ... } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) { .... }... boolean addingToTask = false; boolean movedHome = false; TaskRecord reuseTask = null; if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 && (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0) || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { // If bring to front is requested, and no result is requested, and // we can find a task that was started with this same // component, then instead of launching bring that one to the front. if (r.resultTo == null) { // See if there is a task to bring to the front. If this is // a SINGLE_INSTANCE activity, there can be one and only one // instance of it in the history, and it is always in its own // unique task, so we do a special search. ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE ? findTaskLocked(intent, r.info) : findActivityLocked(intent, r.info); if (taskTop != null) { .... } }...... if (r.packageName != null) { // 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. ActivityRecord top = topRunningNonDelayedActivityLocked(notTop); if (top != null && r.resultTo == null) { ... } } } else { .... } boolean newTask = false; boolean keepCurTransition = false; // Should this be considered a new task? if (r.resultTo == null && !addingToTask && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { if (reuseTask == null) { // todo: should do better management of integers. mService.mCurTask++; if (mService.mCurTask <= 0) { mService.mCurTask = 1; } r.setTask(new TaskRecord(mService.mCurTask, r.info, intent), null, true);//创建一个新的任务,在该任务中启动目标activity if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r + " in new task " + r.task); } else { .... } newTask = true; ... } else if (sourceRecord != null) { ... } else { .... }..... }
activity启动模式有四种:
一:"standard"
(默认模式).系统在启动 Activity 的任务中创建 Activity 的新实例并向其传送 Intent。Activity 可以多次实例化,而每个实例均可属于不同的任务,并且一个任务可以拥有多个实例.
如果目标activity的启动模式是"standard",启动该目标activity时没有添加启动标识(intent没有添加相关flag),那么结果就是在当前的任务中启动该目标activity.比如a应用程序的A activity启动b应用程序中 B activity,这里假设A B 两个activity的启动模式都是standard.那么结果就会在A activity所在任务中启动B activity.看一下源代码:
②
final int startActivityUncheckedLocked(ActivityRecord r, ActivityRecord sourceRecord, int startFlags, boolean doResume, Bundle options) { ... if (sourceRecord == null) { ... } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { .... } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) { .... } if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { .... } boolean addingToTask = false; boolean movedHome = false; TaskRecord reuseTask = null; if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 && (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0) || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { .... }.... if (r.packageName != null) { // 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. ActivityRecord top = topRunningNonDelayedActivityLocked(notTop); if (top != null && r.resultTo == null) { if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) { .... } } } } else { ... } boolean newTask = false; boolean keepCurTransition = false; // Should this be considered a new task? if (r.resultTo == null && !addingToTask && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { .... } else if (sourceRecord != null) { if (!addingToTask && (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) { .... } else if (!addingToTask && (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) { .... } // An existing activity is starting this new activity, so we want // to keep the new one in the same task as the one that is starting // it. r.setTask(sourceRecord.task, sourceRecord.thumbHolder, false);//目标activity和调用者是在同一个任务中 if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r + " in existing task " + r.task); } else { .. } .... }
当启动该目标activity时没有添加启动标识(intent没有添加相关flag),但是A activity的启动模式是"singleInstance" B activity的启动模式依然是"standard",那么结果就会在B activity会在新的任务中启动.看一下源代码:
③
final int startActivityUncheckedLocked(ActivityRecord r, ActivityRecord sourceRecord, int startFlags, boolean doResume, Bundle options) { ... int launchFlags = intent.getFlags(); ..... if (sourceRecord == null) { // This activity is not being started from another... in this // case we -always- start a new task. if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) { .... } } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {//A activity的启动模式是single instance // The original activity who is starting us is running as a single // instance... this new activity it is starting must go on its // own task. launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;//这里就给启动标识赋值成了 new task } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) { ...... } if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { ... } boolean addingToTask = false; boolean movedHome = false; TaskRecord reuseTask = null; if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 && (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0) || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { // If bring to front is requested, and no result is requested, and // we can find a task that was started with this same // component, then instead of launching bring that one to the front. if (r.resultTo == null) { // See if there is a task to bring to the front. If this is // a SINGLE_INSTANCE activity, there can be one and only one // instance of it in the history, and it is always in its own // unique task, so we do a special search. ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE ? findTaskLocked(intent, r.info) : findActivityLocked(intent, r.info); if (taskTop != null) { .... } } } //String uri = r.intent.toURI(); //Intent intent2 = new Intent(uri); //Slog.i(TAG, "Given intent: " + r.intent); //Slog.i(TAG, "URI is: " + uri); //Slog.i(TAG, "To intent: " + intent2); if (r.packageName != null) { // 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. ActivityRecord top = topRunningNonDelayedActivityLocked(notTop); if (top != null && r.resultTo == null) { if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) { .... } } } else { .... } boolean newTask = false; boolean keepCurTransition = false; // Should this be considered a new task? if (r.resultTo == null && !addingToTask && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { if (reuseTask == null) { // todo: should do better management of integers. mService.mCurTask++; if (mService.mCurTask <= 0) { mService.mCurTask = 1; } r.setTask(new TaskRecord(mService.mCurTask, r.info, intent), null, true);//在新的任务中启动 B activity if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r + " in new task " + r.task); } else { ... } newTask = true; if (!movedHome) { moveHomeToFrontFromLaunchLocked(launchFlags); } } else if (sourceRecord != null) { ... } else { ... } ..... }
当启动该目标activity时有添加启动标识FLAG_ACTIVITY_NEW_TASK,A B 两个activity的启动模式都是standard:那么就是①
当然还有很多种情况,这里就不一一列举了,通过源码就很容易知道
二:"singleTop"
.如果当前任务的顶部已存在 Activity 的一个实例,则系统会通过调用该实例的onNewIntent()
方法向其传送 Intent,而不是创建 Activity 的新实例。Activity 可以多次实例化,而每个实例均可属于不同的任务,并且一个任务可以拥有多个实例(但前提是位于返回栈顶部的 Activity 并不是 Activity 的现有实例)
比如现在假设应用程序A 有两个activity a, b. 现在的情况是先打开了a,然后在a中打开b,a的启动模式是"standard",b启动模式是"singleTop",a中启动b时没有添加flag,这样a,b是在同一个task中,现在在b中再启动b,那么结果是不会创建b的实例,只是回到b的onNewIntent()
方法,看源码:
④
final int startActivityUncheckedLocked(ActivityRecord r, ActivityRecord sourceRecord, int startFlags, boolean doResume, Bundle options) { .... if (sourceRecord == null) { // This activity is not being started from another... in this // case we -always- start a new task. if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) { .... } } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { .. } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) { .... } if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { ... } boolean addingToTask = false; boolean movedHome = false; TaskRecord reuseTask = null; if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 && (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0) || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { .... }... if (r.packageName != null) { // 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. ActivityRecord top = topRunningNonDelayedActivityLocked(notTop); if (top != null && r.resultTo == null) { if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) { if (top.app != null && top.app.thread != null) { if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP//b 的启动模式是 single top || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) { .... if (doResume) { resumeTopActivityLocked(null);//直接启动最上面的activity 也就是b } ActivityOptions.abort(options); ..... top.deliverNewIntentLocked(callingUid, r.intent);//这里最终回调b activity的 onNewIntent()方法 return ActivityManager.START_DELIVERED_TO_TOP; } } } } } else { if (r.resultTo != null) { ... } .... }当然还有很多种组合情况,这里就不一一列举了,还是看源码.
三:"singleTask"
.系统创建新任务并实例化位于新任务底部的 Activity。但是,如果该 Activity 的一个实例已存在于一个单独的任务中,则系统会通过调用现有实例的onNewIntent()
方法向其传送 Intent,而不是创建新实例。一次只能存在 Activity 的一个实例.
这启动模式和启动标识FLAG_ACTIVITY_NEW_TASK有相同的功能.先查找目标activity是否有相关联的任务,如果有则肯定会在这个任务中启动(其中又有许多中情况等下看源码),如果不存在相关任务,则创建一个新的任务,在任务中启动目标activity.
看一下源码:
⑤
final int startActivityUncheckedLocked(ActivityRecord r, ActivityRecord sourceRecord, int startFlags, boolean doResume, Bundle options) { ..... int launchFlags = intent.getFlags(); .... if (sourceRecord == null) { .... } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { ... } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {//看到这里,就是当activity的启动模式是这两种的时候 // The activity being started is a single instance... it always // gets launched into its own task. launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;//启动标记被赋值了FLAG_ACTIVITY_NEW_TASK } .... }所以 ③和 ⑤加上启动标识 flag 是FLAG_ACTIVITY_NEW_TASK 这三种情况 的作用是一样的,就是给launchFlags赋值为 FLAG_ACTIVITY_NEW_TASK.
</pre></p><p><span style="font-size:14px;"><span style="font-size:14px;">现在有两种情况当时验证的时候也困扰我一会,最后是通过看源码知道了原因.</span></span></p><p><span style="font-size:14px;"><span style="font-size:14px;">TaskRecord{415d12f0 #6 A com.example.b U 0} Run #6: ActivityRecord{414f0380 u0 com.example.b/.Main2Activity} Run #5: ActivityRecord{415fdd50 u0 com.example.b/.MainActivity} TaskRecord{415312c0 #5 A com.example.a U 0} Run #4: ActivityRecord{415fcc40 u0 com.example.a/.Main2Activity} Run #3: ActivityRecord{414c54d0 u0 com.example.a/.MainActivity}</span></span></p><p><span style="font-size:14px;"><span style="font-size:14px;">现在系统任务的情况如上.有两个应用程序A ,B ,两个应用程序中分别有两个activity,四个activity的启动模式都是standard.</span></span></p><p><span style="font-size:14px;"><span style="font-size:14px;">启动的顺序是先启动A应用程序的第一个activity,这里启动添加了FLAG_ACTIVITY_NEW_TASK标志,所以看上面系统任务的情况知道,A应用程序的第一个activity是在任务的最下面,接着启动A应用程序的第二个activity,没有添加启动标识,所以A应用程序的两个activity是在同一个任务中<span style="font-size:14px;">415312c0 #5,然后在A 应用程序的第二个activity 中启动B应用程序的第一个activity,<span style="font-size:14px;">这里启动添加了</span><span style="font-size:14px;">FLAG_ACTIVITY_NEW_TASK标志,<span style="font-size:14px;">B应用程序的第一个activity是在任务(<span style="font-size:14px;">415d12f0 #6)</span>的最下面,然后继续在B应用程序的第一个activity中启动它的第二activity,没有加启动标识.目前系统的任务情况就如上面所示了.</span></span></span></span></span></p><p><span style="font-size:14px;"><span style="font-size:14px;"><span style="font-size:14px;"><span style="font-size:14px;"><span style="font-size:14px;">现在我要做的是在,B应用程序第二个activity中去启动第一个activity,同时添加启动标识FLAG_ACTIVITY_NEW_TASK.</span></span></span></span></span></p><p><span style="font-size:14px;"><span style="font-size:14px;"><span style="font-size:14px;"><span style="font-size:14px;"><span style="font-size:14px;">结果如:</span></span></span></span></span></p><p><span style="font-size:14px;"><span style="font-size:14px;"><span style="font-size:14px;"><span style="font-size:14px;"><span style="font-size:14px;">TaskRecord{415312c0 #5 A com.example.a U 0} Run #6: ActivityRecord{415fcc40 u0 com.example.a/.Main2Activity} TaskRecord{415d12f0 #6 A com.example.b U 0} Run #5: ActivityRecord{414f0380 u0 com.example.b/.Main2Activity} Run #4: ActivityRecord{415fdd50 u0 com.example.b/.MainActivity} TaskRecord{415312c0 #5 A com.example.a U 0} Run #3: ActivityRecord{414c54d0 u0 com.example.a/.MainActivity}</span></span></span></span></span></p><p><span style="font-size:14px;"><span style="font-size:14px;"><span style="font-size:14px;"><span style="font-size:14px;"><span style="font-size:14px;">通过上面系统任务状态可以知道,现在位于最前面的是A 应用程序的第二个activity,而不是第一个.是不是有点奇怪? 看看源码:</span></span></span></span></span></p><p><span style="font-size:14px;color:#ff0000;"><span style="font-size:14px;"><span style="font-size:14px;"><span style="font-size:14px;"><span style="font-size:14px;">⑥</span></span></span></span></span></p><p><span style="font-size:14px;"><span style="font-size:14px;"><span style="font-size:14px;"><span style="font-size:14px;"><span style="font-size:14px;"></span></span></span></span></span><pre name="code" class="java"> final int startActivityUncheckedLocked(ActivityRecord r, ActivityRecord sourceRecord, int startFlags, boolean doResume, Bundle options) { .... int launchFlags = intent.getFlags(); ... if (sourceRecord == null) { ... } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { ... } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) { ... } if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { ... } boolean addingToTask = false; boolean movedHome = false; TaskRecord reuseTask = null; if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 && (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0) || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { // If bring to front is requested, and no result is requested, and // we can find a task that was started with this same // component, then instead of launching bring that one to the front. if (r.resultTo == null) { // See if there is a task to bring to the front. If this is // a SINGLE_INSTANCE activity, there can be one and only one // instance of it in the history, and it is always in its own // unique task, so we do a special search. ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE ? findTaskLocked(intent, r.info) : findActivityLocked(intent, r.info); if (taskTop != null) {//这里就不为空了,因为A应用程序已经启动过了,它的第一个activity相关的任务也就有了 if (taskTop.task.intent == null) { ... } // If the target task is not in the front, then we need // to bring it to the front... except... well, with // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like // to have the same behavior as if a new instance was // being started, which means not bringing it to the front // if the caller is not itself in the front. ActivityRecord curTop = topRunningNonDelayedActivityLocked(notTop);//这里正在运行的B应用程序的第二个activity if (curTop != null && curTop.task != taskTop.task) {//两个应用程序的任务不相同 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT); boolean callerAtFront = sourceRecord == null || curTop.task == sourceRecord.task; if (callerAtFront) { // We really do want to push this one into the // user's face, right now. movedHome = true; moveHomeToFrontFromLaunchLocked(launchFlags); moveTaskToFrontLocked(taskTop.task, r, options);//这做了任务切换的操作,也就是将A应用程序的所以在任务切换到前台,然后还将任务中最上面的activity启动起来,就是A应用程序的第二个activity. options = null; } } // If the caller has requested that the target task be // reset, then do so. if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) { ... } if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) { .... } if ((launchFlags & (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK)) == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK)) { ... } else if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { ... } else if (r.realActivity.equals(taskTop.task.realActivity)) {//这里很关键,这个条件是当前是成立,r.realActivty是A应用程序的第一个activity,就是我们要 // In this case the top activity on the task is the//启动的activity,tasktop.task.realActivity就是A应用程序所在任务的真正activity是哪个,现在任务中 // same as the one being launched, so we take that//有两个activity,就是A应用程序的两个activity,到底是哪一个呢?答案是第一个activity,这里可以 // as a request to bring the task to the foreground.//认为创建这个任务的activity才是这个任务的realActivity,显然,是第一个activity // If the top activity in the task is the root // activity, deliver this new intent to it if it // desires. if (((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) && taskTop.realActivity.equals(r.realActivity)) { ... } else if (!r.intent.filterEquals(taskTop.task.intent)) { .. } } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) { .. } else if (!taskTop.task.rootWasReset) { .. } if (!addingToTask && reuseTask == 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. if (doResume) { resumeTopActivityLocked(null, options);//走到这里,直接运行最上面的activity,这时最上面的activity就是A应用程序的第二个activity了 因为 } else {//前面切换任务的时候已经启动起来了 ActivityOptions.abort(options); } return ActivityManager.START_TASK_TO_FRONT; } } } }...... }
所以有什么问题直接看源码.
上面的情况,如果我启动是A应用程序的第二个activity呢,同样加FLAG_ACTIVITY_NEW_TASK,结果:
TaskRecord{41670c88 #5 A com.example.a U 0}
Run #8: ActivityRecord{415017d8 u0 com.example.a/.Main2Activity}
TaskRecord{4166a770 #6 A com.example.b U 0}
Run #7: ActivityRecord{4166a820 u0 com.example.b/.Main2Activity}
Run #6: ActivityRecord{416644a0 u0 com.example.b/.MainActivity}
TaskRecord{41670c88 #5 A com.example.a U 0}
Run #5: ActivityRecord{414e2c10 u0 com.example.a/.Main3Activity}
Run #4: ActivityRecord{416c3db0 u0 com.example.a/.Main2Activity}
Run #3: ActivityRecord{415bcd38 u0 com.example.a/.MainActivity}
这里我只是在A应用程序中多加了一个activity,其他启动顺一样,上面是启动A应用中第二个activity后,系统任务的情况.
分析以后,首先任务肯定是切换了,A应用所在的任务切换到了前台,其次在A应用所在的任务中,创建了第二个activity的新实例,注意打印出来没在一起,但是它们确实是在41670c88 #5这个任务中.
所以也验证了A应用程序所在的任务的真正activity是第一个activity.
这里就没再分析源码了,大家有兴趣可以去看看.
其实这里面还有很多其它情况,比如,这些activity的启动模式设置为其他的模式,那么结果可能又不一样.大家可以去实验,然后结合源码分析.
四:"singleInstance"
.与"singleTask"
相同,只是系统不会将任何其他 Activity 启动到包含实例的任务中。该 Activity 始终是其任务唯一仅有的成员;由此 Activity 启动的任何 Activity 均在单独的任务中打开
这个启动模式就不再举例了,前面源码也有分析到了一些情况.
关于启动标识,我这里是重点讲到了FLAG_ACTIVITY_NEW_TASK,还有其他flag,FLAG_ACTIVITY_SINGLE_TOP,FLAG_ACTIVITY_CLEAR_TOP.....就没有一一介绍,大家查阅资料.
另外<activity>
元素的taskAffinity
属性提一下:
final int startActivityUncheckedLocked(ActivityRecord r, ActivityRecord sourceRecord, int startFlags, boolean doResume, Bundle options) { .... if (r.resultTo == null) { // See if there is a task to bring to the front. If this is // a SINGLE_INSTANCE activity, there can be one and only one // instance of it in the history, and it is always in its own // unique task, so we do a special search. ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE ? findTaskLocked(intent, r.info)//在这个方法里面,用到taskAffinity去查找与该activity相关的task : findActivityLocked(intent, r.info); ....
如果一个Activity没有显式的指明该 Activity的taskAffinity,那么它的这个属性就等于Application指明的taskAffinity,如果 Application也没有指明,那么该taskAffinity的值就等于包名。而Task也有自己的affinity属性,它的值等于它的根 Activity的taskAffinity的值.
更多相关文章
- Android模拟按键——源码环境下开发应用程序
- android通过自定义schame和host来启动app
- Android(安卓)BroadcastReceiver基础详解一
- Android(安卓)MVP设计模式登录具体实现Material Design风格
- nexus 7(一代)上android和ubuntu多系统启动(包括ubuntu touch和u
- Android系列之如何使用Alarm
- [置顶] 让你的Android应用与外部元素互动起来
- android日期格式
- Android5.1 SystemUI 启动流程