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启动和退出遵循"后进先出".

Android中的task作用和Activity启动模式以及各种启动Flag的含义_第1张图片

既然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.

现在有两种情况当时验证的时候也困扰我一会,最后是通过看源码知道了原因.
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}
现在系统任务的情况如上.有两个应用程序A ,B ,两个应用程序中分别有两个activity,四个activity的启动模式都是standard.启动的顺序是先启动A应用程序的第一个activity,这里启动添加了FLAG_ACTIVITY_NEW_TASK标志,所以看上面系统任务的情况知道,A应用程序的第一个activity是在任务的最下面,接着启动A应用程序的第二个activity,没有添加启动标识,所以A应用程序的两个activity是在同一个任务中415312c0 #5,然后在A 应用程序的第二个activity 中启动B应用程序的第一个activity,这里启动添加了FLAG_ACTIVITY_NEW_TASK标志,B应用程序的第一个activity是在任务(415d12f0 #6)的最下面,然后继续在B应用程序的第一个activity中启动它的第二activity,没有加启动标识.目前系统的任务情况就如上面所示了.现在我要做的是在,B应用程序第二个activity中去启动第一个activity,同时添加启动标识FLAG_ACTIVITY_NEW_TASK.结果如:
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}
通过上面系统任务状态可以知道,现在位于最前面的是A 应用程序的第二个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) {
      ...
        }

        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.....就没有一一介绍,大家查阅资料.

另外  元素的 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开发)