Activity存储结构变化:从Android2.3到Android4.4

来源:互联网 发布:电脑网络接口类型 编辑:程序博客网 时间:2024/05/21 00:16

由于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。

(2)然而,当系统要查询当前拥有焦点的stack的时候, mFocusedStack是会按照规则返回的,即home在前台就返回home所在的栈的Id,其他程序在前台就返回其他程序所在的栈的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 proceedmHistory.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参数加一。


0 0
原创粉丝点击