再接下来,就是运行模拟器来运行我们的例子了。关于如何在Android源代码工程中运行模拟器,请参考在Ubuntu上下载、编译和安装Android最新源代码一文。
执行以下命令启动模拟器:
USER-NAME@MACHINE-NAME:~/Android$ emulator
模拟器启动起,就可以App Launcher中找到Task应用程序图标,接着把它启动起来:
点击中间的按钮,就会以"singleTask"的方式来启动SubActivity:
现在,我们如何来确认SubActivity是不是在新的任务中启动并且位于这个新任务的堆栈底部呢?Android源代码工程为我们准备了adb工具,可以查看模拟器上系统运行的状况,执行下面的命令查看;
USER-NAME@MACHINE-NAME:~/Android$ adb shell dumpsys activity
这个命令输出的内容比较多,这里我们只关心TaskRecord部分:
Running activities (most recent first):
TaskRecord{4070d8f8 #3 A shy.luo.task}
Run #2: HistoryRecord{406a13f8 shy.luo.task/.SubActivity}
Run #1: HistoryRecord{406a0e00 shy.luo.task/.MainActivity}
TaskRecord{4067a510 #2 A com.android.launcher}
Run #0: HistoryRecord{40677518 com.android.launcher/com.android.launcher2.Launcher}
果然,SubActivity和MainActivity都是运行在TaskRecord#3中,并且SubActivity在MainActivity的上面。这是怎么回事呢?碰到这种情况,Linus Torvalds告诫我们:Read the fucking source code;去年张麻子又说:枪在手,跟我走;我们没有枪,但是有source code,因此,我要说:跟着代码走。
前面我们在两篇文章Android应用程序启动过程源代码分析和Android应用程序内部启动Activity过程(startActivity)的源代码分析时,分别在Step 9和Step 8中分析了Activity在启动过程中与任务相关的函数ActivityStack.startActivityUncheckedLocked函数中,它定义在frameworks/base/services/java/com/android/server/am/ActivityStack.java文件中:
publicclassActivityStack {
......
finalintstartActivityUncheckedLocked(ActivityRecord r,
ActivityRecord sourceRecord, Uri[] grantedUriPermissions,
intgrantedMode,booleanonlyIfNeeded,booleandoResume) {
finalIntent intent = r.intent;
finalintcallingUid = r.launchedFromUid;
intlaunchFlags = intent.getFlags();
......
ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
!= 0? r :null;
......
if(sourceRecord ==null) {
......
} elseif(sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
......
} elseif(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;
}
......
booleanaddingToTask =false;
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((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, true);
if(top !=null) {
......
} 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;
}
} elseif(r.realActivity.equals(taskTop.task.realActivity)) {
......
} elseif((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) ==0) {
......
} elseif(!taskTop.task.rootWasReset) {
......
}
......
}
}
}
......
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)) {
if(top.app !=null&& top.app.thread !=null) {
......
}
}
}
} else{
......
}
booleannewTask =false;
// Should this be considered a new task?
if(r.resultTo ==null&& !addingToTask
&& (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
// todo: should do better management of integers.
mService.mCurTask++;
if(mService.mCurTask <=0) {
mService.mCurTask = 1;
}
r.task = newTaskRecord(mService.mCurTask, r.info, intent,
(r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
if(DEBUG_TASKS) Slog.v(TAG,"Starting new activity "+ r
+ " in new task "+ r.task);
newTask = true;
if(mMainStack) {
mService.addRecentTaskLocked(r.task);
}
} elseif(sourceRecord !=null) {
if(!addingToTask &&
(launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
......
} elseif(!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.task = sourceRecord.task;
......
} else{
......
}
......
startActivityLocked(r, newTask, doResume);
returnSTART_SUCCESS;
}
......
}
首先是获得用来启动Activity的Intent的Flags,并且保存在launchFlags变量中,这里,launcFlags的Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP位没有置位,因此,notTop为null。
接下来的这个if语句:
if(sourceRecord ==null) {
......
} elseif(sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
......
} elseif(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;
}
这里变量r的类型为ActivityRecord,它表示即将在启动的Activity,在这个例子中,即为SubActivity,因此,这里的r.launchMode等于ActivityInfo.LAUNCH_SINGLE_TASK,于是,无条件将launchFlags的Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP位置为1,表示这个SubActivity要在新的任务中启动,但是别急,还要看看其它条件是否满足,如果条件都满足,才可以在新的任务中启动这个SubActivity。
接下将addingToTask变量初始化为false,这个变量也将决定是否要将SubActivity在新的任务中启动,从名字我们就可以看出,默认不增加到原有的任务中启动,即要在新的任务中启动。这里的r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK条成立,条件r.resultTo == null也成立,它表这个Activity不需要将结果返回给启动它的Activity。于是会进入接下来的if语句中,执行:
ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
? findTaskLocked(intent, r.info)
: findActivityLocked(intent, r.info)
这里的条件r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE成立,于是执行findTaskLocked函数,这个函数也是定义在frameworks/base/services/java/com/android/server/am/ActivityStack.java文件中:
publicclassActivityStack {
......
/**
* Returns the top activity in any existing task matching the given
* Intent. Returns null if no such task is found.
*/
privateActivityRecord findTaskLocked(Intent intent, ActivityInfo info) {
ComponentName cls = intent.getComponent();
if(info.targetActivity !=null) {
cls = newComponentName(info.packageName, info.targetActivity);
}
TaskRecord cp = null;
finalintN = mHistory.size();
for(inti=(N-1); i>=0; i--) {
ActivityRecord r = (ActivityRecord)mHistory.get(i);
if(!r.finishing && r.task != cp
&& 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!");
returnr;
}
} elseif(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);
returnr;
} elseif(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);
returnr;
}
}
}
returnnull;
}
......
}
这个函数无非就是根据即将要启动的SubActivity的taskAffinity属性值在系统中查找这样的一个Task:Task的affinity属性值与即将要启动的Activity的taskAffinity属性值一致。如果存在,就返回这个Task堆栈顶端的Activity回去。在上面的AndroidManifest.xml文件中,没有配置MainActivity和SubActivity的taskAffinity属性,于是它们的taskAffinity属性值就默认为父标签application的taskAffinity属性值,这里,标签application的taskAffinity也没有配置,于是它们就默认为包名,即"shy.luo.task"。由于在启动SubActivity之前,MainActivity已经启动,MainActivity启动的时候,会在一个新的任务里面启动,而这个新的任务的affinity属性就等于它的第一个Activity的taskAffinity属性值。于是,这个函数会动回表示MainActivity的ActivityRecord回去.
回到前面的startActivityUncheckedLocked函数中,这里的taskTop就表示MainActivity,它不为null,于是继续往前执行。由于条件r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK成立,于是执行下面语句:
ActivityRecord top = performClearTaskLocked(
kTop.task.taskId, r, launchFlags, true);
函数performClearTaskLocked也是定义在frameworks/base/services/java/com/android/server/am/ActivityStack.java文件中:
publicclassActivityStack {
......
/**
* Perform clear operation as requested by
* {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
* stack to the given task, then look for
* an instance of that activity in the stack and, if found, finish all
* activities on top of it and return the instance.
*
* @param newR Description of the new activity being started.
* @return Returns the old activity that should be continue to be used,
* or null if none was found.
*/
privatefinalActivityRecord performClearTaskLocked(inttaskId,
ActivityRecord newR, intlaunchFlags,booleandoClear) {
inti = mHistory.size();
// First find the requested task.
while(i >0) {
i--;
ActivityRecord r = (ActivityRecord)mHistory.get(i);
if(r.task.taskId == taskId) {
i++;
break;
}
}
// Now clear it.
while(i >0) {
i--;
ActivityRecord r = (ActivityRecord)mHistory.get(i);
if(r.finishing) {
continue;
}
if(r.task.taskId != taskId) {
returnnull;
}
if(r.realActivity.equals(newR.realActivity)) {
// Here it is! Now finish everything in front...
ActivityRecord ret = r;
if(doClear) {
while(i
i++;
r = (ActivityRecord)mHistory.get(i);
if(r.finishing) {
continue;
}
if(finishActivityLocked(r, i, Activity.RESULT_CANCELED,
null,"clear")) {
i--;
}
}
}
// Finally, if this is a normal launch mode (that is, not
// expecting onNewIntent()), then we will finish the current
// instance of the activity so a new fresh one can be started.
if(ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
&& (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
if(!ret.finishing) {
intindex = indexOfTokenLocked(ret);
if(index >=0) {
finishActivityLocked(ret, index, Activity.RESULT_CANCELED,
null,"clear");
}
returnnull;
}
}
returnret;
}
}
returnnull;
}
......
}
这个函数中作用无非就是找到ID等于参数taskId的任务,然后在这个任务中查找是否已经存在即将要启动的Activity的实例,如果存在,就会把这个Actvity实例上面直到任务堆栈顶端的Activity通过调用finishActivityLocked函数将它们结束掉。在这个例子中,就是要在属性值affinity等于"shy.luo.task"的任务中看看是否存在SubActivity类型的实例,如果有,就把它上面的Activity都结束掉。这里,属性值affinity等于"shy.luo.task"的任务只有一个MainActivity,而且它不是SubActivity的实例,所以这个函数就返回null了。