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

由于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 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参数加一。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值