一般情况下启动activity的时候不需要指定launchMode,不指定launchMode时,使用的时默认值,默认值时standard。standard属性在运行时会被解析成FLAG_ACTIVITY_MULTIPLE_TASK,因而源码中就是用这个flag来处理standard类型的。
如果需要指定launchMode,则有两种方式,第一种方式时使用xml属性launchMode来指定,第二种方式是通过在代码中启动activity时指定flag。示例如下:
在AndroidManifest中除了通过launchMode标签设置Activity启动模式外,还可以通过taskAffinity标签来标识Activity所属于的任务,用taskAffinity来给activity分组。不论使用了默认的launchMode还是指定了launchMode,都可以通过查看当前activity返回栈信息来调试。使用如下命令可以查看当前activity的返回栈信息:
adb shell dumpsys activity activities
如果启动activity 的顺序是Main -> A ->B ->C-> A (FLAG_NEW_TASK),未说明的都使用默认的launchMode,则该命令的执行结果如下:
ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Display #0 (activities from top to bottom):
Stack #1:
mResumedActivity=ActivityRecord{dceffaf u0 com.anly.samples/.activity.AActivity t728}
Task id #728
* TaskRecord{d5cf06d #728 A=com.anly.aactivity U=0 StackId=1 sz=1}
affinity=com.anly.aactivity
intent={flg=0x10000000 cmp=com.anly.samples/.activity.AActivity}
realActivity=com.anly.samples/.activity.AActivity
* Hist #0: ActivityRecord{dceffaf u0 com.anly.samples/.activity.AActivity t728}
packageName=com.anly.samples processName=com.anly.samples
frontOfTask=true task=TaskRecord{d5cf06d #728 A=com.anly.aactivity U=0 StackId=1 sz=1}
taskAffinity=com.anly.aactivity
realActivity=com.anly.samples/.activity.AActivity
resizeMode=RESIZE_MODE_RESIZEABLE
realComponentName=com.anly.samples/.activity.AActivity
Task id #727
* TaskRecord{321c4a2 #727 A=com.anly.samples U=0 StackId=1 sz=5}
affinity=com.anly.samples
intent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.anly.samples/.MainActivity}
realActivity=com.anly.samples/.MainActivity
* Hist #4: ActivityRecord{c127d42 u0 com.anly.samples/.activity.CActivity t727}
taskAffinity=com.anly.samples
realActivity=com.anly.samples/.activity.CActivity
realComponentName=com.anly.samples/.activity.CActivity
* Hist #3: ActivityRecord{b05e751 u0 com.anly.samples/.activity.BActivity t727}
taskAffinity=com.anly.samples
* Hist #2: ActivityRecord{ae468bf u0 com.anly.samples/.activity.AActivity t727}
taskAffinity=com.anly.aactivity
* Hist #1: ActivityRecord{dec47c7 u0 com.anly.samples/.MainActivity t727}
taskAffinity=com.anly.samples
realActivity=com.anly.samples/.MainActivity
state=STOPPED stopped=true delayedResume=false finishing=false
mActivityType=APPLICATION_ACTIVITY_TYPE
resizeMode=RESIZE_MODE_RESIZEABLE
realComponentName=com.anly.samples/.MainActivity
从以上返回栈信息中可以看出,整个app的返回栈对应于一个stack#1,
Display #0 (activities from top to bottom):
Stack #1:
并且activity返回栈信息按照从上到下的方式列举如下,有两个task,分别为Task id #728和Task id #727,每个task都包含一些activity。task的属性是通过TaskRecord来描述的,有几个重要的属性值分别是affinity,intent和realActivity。
Task id #728
...
Task id #727
...
值得注意的是,如果在xml中指定了taskAffinity,比如指定taskAffinity为com.anly.aactivity,则在该示例中Task id#728中对应于AActivity,AActivity的属性是通过ActivityRecord来描述的,它的taskAffinity就是com.anly.aactivity。同样地,AActivity所在的task的affinity也是com.anly.aactivity。这里是一一对应的。
* Hist #0: ActivityRecord{dceffaf u0 com.anly.samples/.activity.AActivity t728}
packageName=com.anly.samples processName=com.anly.samples
frontOfTask=true task=TaskRecord{d5cf06d #728 A=com.anly.aactivity U=0 StackId=1 sz=1}
taskAffinity=com.anly.aactivity
realActivity=com.anly.samples/.activity.AActivity
resizeMode=RESIZE_MODE_RESIZEABLE
realComponentName=com.anly.samples/.activity.AActivity
如果没有在xml中指定taskAffinity,一般这是更常见的使用场景,这种情况下,ActivityRecord中也存在taskAffinity,只不过taskAffinity使用的是默认值,为包名。比如task id#727中的CActivity,它的taskAffinity就是com.anly.samples,和包名相同。
Task id #727
* TaskRecord{321c4a2 #727 A=com.anly.samples U=0 StackId=1 sz=5}
affinity=com.anly.samples
intent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.anly.samples/.MainActivity}
realActivity=com.anly.samples/.MainActivity
* Hist #4: ActivityRecord{c127d42 u0 com.anly.samples/.activity.CActivity t727}
taskAffinity=com.anly.samples
realActivity=com.anly.samples/.activity.CActivity
realComponentName=com.anly.samples/.activity.CActivity
对activity返回栈信息有了总体把握之后,再去阅读源码,就很容易理解activity不同的启动模式在源码中是怎么工作的了。
这里以4.3的源码为例,在源码中处理activity启动模式的代码在ActivityStack.java类中,处理逻辑是在startActivityUncheckedLocked这个方法中实现的。它属于activity启动流程中的一个环节,activity启动流程涉及到非常多的技术点,感兴趣的同学可以找相关文章阅读。这里重点分析startActivityUncheckedLocked方法的工作原理。
final int startActivityUncheckedLocked(ActivityRecord r,
ActivityRecord sourceRecord, int startFlags, boolean doResume,
Bundle options) {
final Intent intent = r.intent;
final int callingUid = r.launchedFromUid;
int launchFlags = intent.getFlags();
// We'll invoke onUserLeaving before onPause only if the launching
// activity did not explicitly state that this is an automated launch.
mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
if (DEBUG_USER_LEAVING) Slog.v(TAG,
"startActivity() => mUserLeaving=" + mUserLeaving);
// If the caller has asked not to resume at this point, we make note
// of this in the record so that we can skip it when trying to find
// the top running activity.
if (!doResume) {
r.delayedResume = true;
}
ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
!= 0 ? r : null;
// If the onlyIfNeeded flag is set, then we can do this if the activity
// being launched is the same as the one making the call... or, as
// a special case, if we do not know the caller then we count the
// current top activity as the caller.
if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
ActivityRecord checkedCaller = sourceRecord;
if (checkedCaller == null) {
checkedCaller = topRunningNonDelayedActivityLocked(notTop);
}
if (!checkedCaller.realActivity.equals(r.realActivity)) {
// Caller is not the same as launcher, so always needed.
startFlags &= ~ActivityManager.START_FLAG_ONLY_IF_NEEDED;
}
}
...
这段代码重点是int launchFlags = intent.getFlags();这一句,获取指定的flag。其余的代码是做一些容错或者系统检查,和launchMode的应用场景没关系,略过即可。接着往下看
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) {
Slog.w(TAG, "startActivity called from non-Activity context; " +
"forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
+ intent);
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
}
} else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_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;
} else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
// The activity being started is a single instance... it always
// gets launched into its own task.
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
}
这段代码是为了给 launchFlags增加FLAG_ACTIVITY_NEW_TASK。sourceRecord即启动目标activity的源activity。源码里activity是通过ActivityRecord类来管理的,所以sourceRecord的类型是ActivityRecord类型。
这三种情况都需要给launchFlags增加FLAG_ACTIVITY_NEW_TASK,这样就把launchFlags准备好了。下面就是根据launchFlags设置的flag值进行对应的处理了。
不过在这之前又是一个容错处理,它的意思是,如果目标activity是有返回结果的,而此时目标activity还没有启动不应该有返回结果,所以需要把返回结果置为null,并且返回一个RESULT_CANCELED结果。
if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
// For whatever reason this activity is being launched into a new
// task... yet the caller has requested a result back. Well, that
// is pretty messed up, so instead immediately send back a cancel
// and let the new task continue launched as normal without a
// dependency on its originator.
Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
sendActivityResultLocked(-1,
r.resultTo, r.resultWho, r.requestCode,
Activity.RESULT_CANCELED, null);
r.resultTo = null;
}
下面就是根据launchFlags设置的flag值进行对应的处理了。注意launchFlags是目标activity的flag集合,而不是源activity的。
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) {
这里有三种情况可以进入下面的处理逻辑。
这里需要说明的是,r.launchMode的值只有四个,以常量的形式定义在ActivityInfo里,
/**
* Constant corresponding to standard
in
* the {@link android.R.attr#launchMode} attribute.
*/
public static final int LAUNCH_MULTIPLE = 0;
/**
* Constant corresponding to singleTop
in
* the {@link android.R.attr#launchMode} attribute.
*/
public static final int LAUNCH_SINGLE_TOP = 1;
/**
* Constant corresponding to singleTask
in
* the {@link android.R.attr#launchMode} attribute.
*/
public static final int LAUNCH_SINGLE_TASK = 2;
/**
* Constant corresponding to singleInstance
in
* the {@link android.R.attr#launchMode} attribute.
*/
public static final int LAUNCH_SINGLE_INSTANCE = 3;
与此对应的是Intent的FLAG常量值,他们定义在Intent类中,常用的常量值有
/**
* If set, the activity will not be launched if it is already running
* at the top of the history stack.
*/
public static final int FLAG_ACTIVITY_SINGLE_TOP = 0x20000000;
/**
* If set, this activity will become the start of a new task on this
* history stack. A task (from the activity that started it to the
* next task activity) defines an atomic group of activities that the
* user can move to. Tasks can be moved to the foreground and background;
* all of the activities inside of a particular task always remain in
* the same order.
*/
public static final int FLAG_ACTIVITY_NEW_TASK = 0x10000000;
/**
* This flag is ignored if
* {@link #FLAG_ACTIVITY_NEW_TASK} is not set.
*/
public static final int FLAG_ACTIVITY_MULTIPLE_TASK = 0x08000000;
/**
* If set, and the activity being launched is already running in the
* current task, then instead of launching a new instance of that activity,
* all of the other activities on top of it will be closed and this Intent
* will be delivered to the (now on top) old activity as a new Intent.
*/
public static final int FLAG_ACTIVITY_CLEAR_TOP = 0x04000000;
虽然Intent的FLAG也有四个,但是他们并不是和ActivityInfo中的值一一对应的。只有SingleTop和Standard是两者共有的。
回到上面说的三种条件,如果满足任何一种条件,就会进入后续逻辑,执行下面的操作。
// 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);
这个逻辑非常重要,网上很多介绍launchMode的文章之所以讲不清楚甚至讲解错误就是因为这段代码看错了。
这里拿目标activity的launchMode去对比,如果不是LAUNCH_SINGLE_INSTANCE,则走findTaskLocked方法,如果是LAUNCH_SINGLE_INSTANCE则走findActivityLocked方法。
理解这段代码有个小技巧,想一下上文讲的返回栈信息,一个stack对应多个task,一个task对应多个activity的结构。用表格简单描述这种数据结构如下
task #728 | activityA0、activityB0、activityC0、... | |
stack | task#727 | activityA1、activityB1、activityC1、... |
task#726 | activityA2、activityB2、activityC2、... |
这里判断的时候,如果不是singleInstance模式,就走findTaskLocked,意思是遍历某个特定task里的activity,比如遍历task#728的activityA0、activityB0、activityC0、...
如果是singleInstance模式,则走findActivityLocked,意思是遍历所有task里的所有activity,这种情况会遍历
findTaskLocked源码如下,
private ActivityRecord findTaskLocked(Intent intent, ActivityInfo info) {
ComponentName cls = intent.getComponent();
if (info.targetActivity != null) {
cls = new ComponentName(info.packageName, info.targetActivity);
}
TaskRecord cp = null;
final int userId = UserHandle.getUserId(info.applicationInfo.uid);
final int N = mHistory.size();
for (int i=(N-1); i>=0; i--) {
ActivityRecord r = mHistory.get(i);
if (!r.finishing && r.task != cp && r.userId == userId
&& r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
cp = r.task;
//Slog.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
// + "/aff=" + r.task.affinity + " to new cls="
// + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
if (r.task.affinity != null) {
if (r.task.affinity.equals(info.taskAffinity)) {
//Slog.i(TAG, "Found matching affinity!");
return r;
}
} else if (r.task.intent != null
&& r.task.intent.getComponent().equals(cls)) {
//Slog.i(TAG, "Found matching class!");
//dump();
//Slog.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
return r;
} else if (r.task.affinityIntent != null
&& r.task.affinityIntent.getComponent().equals(cls)) {
//Slog.i(TAG, "Found matching class!");
//dump();
//Slog.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
return r;
}
}
}
return null;
}
它是从N-1开始向前遍历的,符合栈后进先出的特性。并且在for循环里最外层的if条件中有 r.task != cp的判断,这个判断就可以保证找到特定的task。并且这里返回的是目标task顶端第一个activity。需要注意的是,虽然在这里从N-1开始称之为从后向前遍历,但是从用户角度看,N-1是返回栈最顶部的activity,0是最底部的activity,是被其他activity盖住的。也就是这里说的“后”,对应于视觉上最顶部的activity。
findActivityLocked源码如下
/**
* Returns the first activity (starting from the top of the stack) that
* is the same as the given activity. Returns null if no such activity
* is found.
*/
private ActivityRecord findActivityLocked(Intent intent, ActivityInfo info) {
ComponentName cls = intent.getComponent();
if (info.targetActivity != null) {
cls = new ComponentName(info.packageName, info.targetActivity);
}
final int N = mHistory.size();
for (int i=(N-1); i>=0; i--) {
ActivityRecord r = (ActivityRecord)mHistory.get(i);
if (!r.finishing) {
if (r.intent.getComponent().equals(cls)) {
//Slog.i(TAG, "Found matching class!");
//dump();
//Slog.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
return r;
}
}
}
return null;
}
它不区分task,是从后向前遍历的整个mHistory,而mHistory对应的就是activity返回栈信息中的stack。因而这里也就清楚singleInstance的工作原理了,他是整个app的stack里唯一的,这也就是为什么称之为单例的原因。与此对比,singleTask指的是特定task内唯一的,不同task内可以不唯一。这就是两者的区别。
继续往下看
if (taskTop != null) {
if (taskTop.task.intent == null) {
// This task was started because of movement of
// the activity based on affinity... now that we
// are actually launching it, we can assign the
// base intent.
taskTop.task.setIntent(intent, r.info);
// 727 A
}
// 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);
// AAcitivty=curTop 728 AAcitivty
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);
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) {
taskTop = resetTaskIfNeededLocked(taskTop, r);
}
if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
// We don't need to start a new activity, and
// the client said not to do anything if that
// is the case, so this is it! And for paranoia, make
// sure we have correctly resumed the top activity.
if (doResume) {
resumeTopActivityLocked(null, options);
} else {
ActivityOptions.abort(options);
}
return ActivityManager.START_RETURN_INTENT_TO_CALLER;
}
if ((launchFlags &
(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK))
== (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK)) {
// The caller has requested to completely replace any
// existing task with its new activity. Well that should
// not be too hard...
reuseTask = taskTop.task;
performClearTaskLocked(taskTop.task.taskId);
reuseTask.setIntent(r.intent, r.info);
} else if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
// In this situation we want to remove all activities
// from the task up to the one being started. In most
// cases this means we are resetting the task to its
// initial state.
ActivityRecord top = performClearTaskLocked(
taskTop.task.taskId, r, launchFlags);
if (top != null) {
if (top.frontOfTask) {
// Activity aliases may mean we use different
// intents for the top activity, so make sure
// the task now has the identity of the new
// intent.
top.task.setIntent(r.intent, r.info);
}
logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
top.deliverNewIntentLocked(callingUid, r.intent);
} else {
// A special case: we need to
// start the activity because it is not currently
// running, and the caller has asked to clear the
// current task to have this activity at the top.
addingToTask = true;
// Now pretend like this activity is being started
// by the top of its task, so it is put in the
// right place.
sourceRecord = taskTop;
}
} else if (r.realActivity.equals(taskTop.task.realActivity)) {
// In this case the top activity on the task is the
// same as the one being launched, so we take that
// as a request to bring the task to the foreground.
// 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)) {
logStartActivity(EventLogTags.AM_NEW_INTENT, r, taskTop.task);
if (taskTop.frontOfTask) {
taskTop.task.setIntent(r.intent, r.info);
}
taskTop.deliverNewIntentLocked(callingUid, r.intent);
} else if (!r.intent.filterEquals(taskTop.task.intent)) {
// In this case we are launching the root activity
// of the task, but with a different intent. We
// should start a new instance on top.
addingToTask = true;
sourceRecord = taskTop;
}
} else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
// In this case an activity is being launched in to an
// existing task, without resetting that task. This
// is typically the situation of launching an activity
// from a notification or shortcut. We want to place
// the new activity on top of the current task.
addingToTask = true;
sourceRecord = taskTop;
} else if (!taskTop.task.rootWasReset) {
// In this case we are launching in to an existing task
// that has not yet been started from its front door.
// The current task has been brought to the front.
// Ideally, we'd probably like to place this new task
// at the bottom of its stack, but that's a little hard
// to do with the current organization of the code so
// for now we'll just drop it.
taskTop.task.setIntent(r.intent, r.info);
}
// 不是NEW_TASK,也不是CLEAR_TASK
// 且找到了那个目标activity,不论是singleTask,singleInstance还是singleTop
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);
} else {
ActivityOptions.abort(options);
}
return ActivityManager.START_TASK_TO_FRONT;
}
}
如果找到了taskTop,则进入唤醒逻辑,否则创建新的。唤醒逻辑里有两个因素会影响到具体执行流程,一个是刚才找到的要被唤醒的taskTop,一个是当前返回栈栈顶的activity,源码里称之为curTop。
这里就处理完了上文三种情况。为了方便对比这里再次罗列下那三种情况。
那这三种情况处理完之后,可以看到除了FLAG_ACTIVITY_NEW_TASK && FLAG_ACTIVITY_CLEAR_TASK的情况return之外,其余情况并没有return而是继续向下执行。继续向下执行的情况有
这些情况在执行过程中有些情况的组合会被处理且提前return,比如FLAG_ACTIVITY_SINGLE_TOP,LAUNCH_SINGLE_TOP和LAUNCH_SINGLE_TASK。不满足提前return条件的则继续向下执行,
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
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
// For paranoia, make sure we have correctly
// resumed the top activity.
if (doResume) {
resumeTopActivityLocked(null);
}
ActivityOptions.abort(options);
if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
// We don't need to start a new activity, and
// the client said not to do anything if that
// is the case, so this is it!
return ActivityManager.START_RETURN_INTENT_TO_CALLER;
}
top.deliverNewIntentLocked(callingUid, r.intent);
return ActivityManager.START_DELIVERED_TO_TOP;
}
}
}
}
} else {
if (r.resultTo != null) {
sendActivityResultLocked(-1,
r.resultTo, r.resultWho, r.requestCode,
Activity.RESULT_CANCELED, null);
}
ActivityOptions.abort(options);
return ActivityManager.START_CLASS_NOT_FOUND;
}
先拿到当前前台可见的activity这里命名为top,如果top非空,且top.realActivity和目标r.realActivity一致,则继续判断是否有FLAG_ACTIVITY_SINGLE_TOP或者FLAG_ACTIVITY_SINGLE_TASK,LAUNCH_SINGLE_TASK。如果满足条件则通过deliverNewIntentLocked调用目标activity的onNewIntent方法。
else分支是容错处理,略过,继续往下看。
// 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);
if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+ " in new task " + r.task);
} else {
r.setTask(reuseTask, reuseTask, true);
}
newTask = true;
if (!movedHome) {
moveHomeToFrontFromLaunchLocked(launchFlags);
}
} else if (sourceRecord != null) {
if (!addingToTask &&
(launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
// In this case, we are adding the activity to an existing
// task, but the caller has asked to clear that task if the
// activity is already running.
ActivityRecord top = performClearTaskLocked(
sourceRecord.task.taskId, r, launchFlags);
keepCurTransition = true;
if (top != null) {
logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
top.deliverNewIntentLocked(callingUid, r.intent);
// For paranoia, make sure we have correctly
// resumed the top activity.
if (doResume) {
resumeTopActivityLocked(null);
}
ActivityOptions.abort(options);
return ActivityManager.START_DELIVERED_TO_TOP;
}
} else if (!addingToTask &&
(launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
// In this case, we are launching an activity in our own task
// that may already be running somewhere in the history, and
// we want to shuffle it to the front of the stack if so.
int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
if (where >= 0) {
ActivityRecord top = moveActivityToFrontLocked(where);
logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
top.updateOptionsLocked(options);
top.deliverNewIntentLocked(callingUid, r.intent);
if (doResume) {
resumeTopActivityLocked(null);
}
return ActivityManager.START_DELIVERED_TO_TOP;
}
}
// 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);
if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+ " in existing task " + r.task);
} else {
// This not being started from an existing activity, and not part
// of a new task... just put it in the top task, though these days
// this case should never happen.
final int N = mHistory.size();
ActivityRecord prev =
N > 0 ? mHistory.get(N-1) : null;
r.setTask(prev != null
? prev.task
: new TaskRecord(mService.mCurTask, r.info, intent), null, true);
if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+ " in new guessed " + r.task);
}
一般情况下,都是用默认值或者仅仅指定某一个启动属性,这时都会走这块逻辑。具体是
// 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);
继续执行,通过startActivityLocked来启动一个新的activity。
startActivityLocked(r, newTask, doResume, keepCurTransition, options);
否则,就如注释所说these days this case should never happen.略。
至此,所以流程处理完毕。
总结一下,理解launchMode,需要现在脑海中建立那个activity返回栈信息从而有个总体印象,然后再去阅读代码。代码分成两大部分,分别对应上文说的三种情况以及后续的情况。这些情况有些在执行时就提前return完成了处理,有些则不会return继续向下执行直到方法结束。这也是整体代码比较难懂的原因。只要梳理清楚了那些条件会return哪些不会,正确的执行流程就可以掌握了,然后在仔细分析具体的复用机制就可以完全掌握了。
感兴趣的或者有问题的欢迎留言交流。