由于Android2.3操作系统的普及性,现有的对于Activity存储结构的分析大多是针对Android2.3的,但是,在目前最新的Android4.4中,Activity的存储结构发生了一些变化。下面就对这一变化做一描述。
基础知识:activity在AMS中的形式是ActivityRecord,task在AMS中的形式为TaskRecord,进程在AMS中的管理形式为ProcessRecord。
一、Android2.3中Activity的存储结构
存储结构示意图:
AMS提供了一个ArrayList mHistory来管理所有的activity。
由上面的示意图可以得知:
(1)所有的ActivityRecord会被存储在mHistory管理;.
(2) 每个ActivityRecord会对应到一个TaskRecord,并且有着相同TaskRecord的ActivityRecord在mHistory中会处在连续的位置;
(3)同一个TaskRecord的Activity可能分别处于不同的进程中,每个Activity所处的进程跟task没有关系。
二、Android4.4中Activity的存储结构
在Android4.4中,并不采用原先的mHistory来管理所有的Activity,而是按层次进行管理。
由上图可以得知;
(1)在管理层次的最上层是一个ActivityStack类型的数组mStacks,用于管理所有的ActivityStack。
(2)当前,系统中只有两个ActivityStack,一个是mHomeStack,用于保存Launcher的Activity,另一个是mFocusedStack,用于保存非Launcher的App的Activity。
(3)mStacks数组中,只有上述的两个栈,设置数组的目的可能是为以后版本的多用户情况考虑,可能每个用户分别拥有自己的一个Activity,运行自己的App,当然这只是猜测。
(4)在每个ActivityStack中,都可以拥有多个TaskRecord。这些TaskRecord存储在ActivityStack.java:ArrayList<TaskRecord> mTaskHistory之中。
(5)在TaskRecord中,包含ArrayList<ActivityRecord> mActivities,用于存放该Task中的所有的Activity的信息;包含ActivityStack stack,用于记录所属的栈;包含int numActivities,用于记录当前Task中的Activity数量。
(6)Stack和Task中的存储:通过加断点对系统进行调试得知,mTaskHistory默认是一个容量为12的数组,当开的Task多于12个时,再开辟6个TaskRecord的用于存放新的Task信息。多于18个Task的情况没有进行测试。mStacks和mTaskHistory的存储情况相同。
(7)综合上面的分析可知,要想找到某个Activity,需要按层次查找:先找到对应的栈,再找到栈中的Task,再在该Task中查找Activity。
需要注意的是:
(1)不论Launcher(即Home)在前台还是后台,mFocusedStack的Id始终都是非Launcher所在的Stack的Id。
三、向已有的Task中添加一个Activity
既然Android2.3和Android4.4中对Activity的存储方式存在差异,那么添加一个新的Activity的时候,添加方法也是有差异的。
分析Activity的启动过程(具体可以查看老罗的《Android源代码情景分析》一书),在ActivityStack.startActivityUncheckedLocked函数中会判断决定是否需要为新开启的Activity创建新的Task,如果需要创建,那么就创建新的Task,如果不需要创建,那么就将Activity添加到原先已经存在的Task中。在此,我们只考虑后一种情况。进行完上述操作之后,执行ActivityStack.startActivityLocked()将Activity添加到Task中(ASS中也有startActivityLocked(),注意不要混淆)。
在Android2.3中:
public class ActivityStack {
......
private final void startActivityLocked(ActivityRecord r, boolean newTask,
boolean doResume) {
final int NH = mHistory.size();
int addPos = -1;
if (!newTask) {
// If starting in an existing task, find where that is...
boolean startIt = true;
for (int i = NH-1; i >= 0; i--) {
ActivityRecord p = (ActivityRecord)mHistory.get(i);
if (p.finishing) {
continue;
}
if (p.task == r.task) {
// Here it is! Now, if this is not yet visible to the
// user, then just add it without starting; it will
// get started when the user navigates back to it.
addPos = i+1;
if (!startIt) {
mHistory.add(addPos, r);
r.inHistory = true;
r.task.numActivities++;
mService.mWindowManager.addAppToken(addPos, r, r.task.taskId,
r.info.screenOrientation, r.fullscreen);
if (VALIDATE_TOKENS) {
mService.mWindowManager.validateAppTokens(mHistory);
}
return;
}
break;
}
if (p.fullscreen) {
startIt = false;
}
}
}
......
// Slot the activity into the history stack and proceed
mHistory.add(addPos, r);
r.inHistory = true;
r.frontOfTask = newTask;
r.task.numActivities++;
......
if (doResume) {
resumeTopActivityLocked(null);
}
}
......
}
由上述代码可知:
在Android2.3中,由于以下三个原因:(1)Activity是统一由mHistory数组来管理的(2)属于同一个Task的所有Activity都连续存放(3)新开启的Activity存放位置在以前开启的Activity之上,所以,当要添加新的Activity的时候,直接从上到下遍历mHistory数组,当检查到某个ActivityRecord所属的Task与新添加的Activity所属的Task相同时,记录该Activity在mHistory中的存放位置i,addPos=i+1即为要添加的Activity在mHistory中的位置,调用mHistory.add(addPos,r)就将Activity添加到mHistory数组中了。与此同时,满足了上述的三点要求。
在Android4.4中:
TaskRecord task = null;
if (!newTask) {
// If starting in an existing task, find where that is...
boolean startIt = true;
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
task = mTaskHistory.get(taskNdx);
if (task == r.task) {
// Here it is! Now, if this is not yet visible to the
// user, then just add it without starting; it will
// get started when the user navigates back to it.
if (!startIt) {
if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task "
+ task, new RuntimeException("here").fillInStackTrace());
task.addActivityToTop(r);
r.putInHistory();
mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
(r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0,
r.userId);
if (VALIDATE_TOKENS) {
validateAppTokensLocked();
}
ActivityOptions.abort(options);
return;
}
break;
} else if (task.numFullscreen > 0) {
startIt = false;
}
}
}
由上述代码可以看出:
在Android4.4中,首先会从上到下遍历mTaskHistory数组,找到要启动的Activity所属的Task,之后直接调用Task.addActivityToTop(r)将Activity加入到该Task即可。接着调用r.puInHistory()进行善后事宜:
void putInHistory() {
if (!inHistory) {
inHistory = true;
if (task != null && !finishing) {
task.numActivities++;
}
}
}
在该函数中,将inHistory标志位设置为TRUE,将所述的Task的numActivities参数加一。