分析点击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的值.




  


更多相关文章

  1. Android模拟按键——源码环境下开发应用程序
  2. android通过自定义schame和host来启动app
  3. Android(安卓)BroadcastReceiver基础详解一
  4. Android(安卓)MVP设计模式登录具体实现Material Design风格
  5. nexus 7(一代)上android和ubuntu多系统启动(包括ubuntu touch和u
  6. Android系列之如何使用Alarm
  7. [置顶] 让你的Android应用与外部元素互动起来
  8. android日期格式
  9. Android5.1 SystemUI 启动流程

随机推荐

  1. Create Native iOS, Android, Mac and Wi
  2. Android(安卓)Thread线程
  3. 获取Android系统信息
  4. android sqlite 图片保存和读出
  5. android SQLite数据库基本操作示例
  6. android使用GPS
  7. android 虚拟摇杆绘制
  8. Android 加载服务器上的图片
  9. android中的状态保存
  10. Android Studio Error:Execution failed