相关文章
Android系统启动流程系列
Android应用进程系列
Android深刻四大组件系列
Android深刻解析AMS系列html
关于AMS,原计划是只写一篇文章来介绍,可是AMS功能繁多,一篇文章的篇幅远远不够。这一篇咱们接着来学习与AMS相关的ActivityTask和Activity栈管理。
java
ActivityStack从名称来看是跟栈相关的类,其实它是一个管理类,用来管理系统全部Activity的各类状态。它由ActivityStackSupervisor来进行管理的,而ActivityStackSupervisor在AMS中的构造方法中被建立。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.javaandroid
public ActivityManagerService(Context systemContext) {
...
mStackSupervisor = new ActivityStackSupervisor(this);
...
}复制代码
ActivityStackSupervisor中有多种ActivityStack实例,以下所示。
frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java微信
public final class ActivityStackSupervisor implements DisplayListener {
...
ActivityStack mHomeStack;
ActivityStack mFocusedStack;
private ActivityStack mLastFocusedStack;
...
}复制代码
mHomeStack用来存储Launcher App的Activity的堆栈,mFocusedStack表示当前正在接收输入或启动下一个Activity的堆栈。mLastFocusedStack表示此前接收输入的Activity的堆栈。ide
经过ActivityStackSupervisor提供了获取上述ActivityStack的方法,好比要获取mFocusedStack,只须要调用ActivityStackSupervisor的getFocusedStack方法就能够了:
frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java学习
ActivityStack getFocusedStack() {
return mFocusedStack;
}复制代码
ActivityStack中经过枚举存储了Activity的全部的状态,以下所示。
frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java动画
enum ActivityState {
INITIALIZING,
RESUMED,
PAUSING,
PAUSED,
STOPPING,
STOPPED,
FINISHING,
DESTROYING,
DESTROYED
}复制代码
经过名称咱们能够很轻易知道这些状态所表明的意义。应用ActivityState的场景会有不少,好比下面的代码:
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.javathis
@Override
public void overridePendingTransition(IBinder token, String packageName, int enterAnim, int exitAnim) {
...
if (self.state == ActivityState.RESUMED
|| self.state == ActivityState.PAUSING) {//1
mWindowManager.overridePendingAppTransition(packageName,
enterAnim, exitAnim, null);
}
Binder.restoreCallingIdentity(origId);
}
}复制代码
overridePendingTransition方法用于设置Activity的切换动画,注释1处能够看到只有ActivityState为RESUMED状态或者PAUSING状态时才会调用WMS类型的mWindowManager对象的overridePendingAppTransition方法来进行切换动画。spa
在ActivityStack中定义了一些特殊状态的Activity,以下所示。.net
ActivityRecord mPausingActivity = null;//正在暂停的Activity
ActivityRecord mLastPausedActivity = null;//上一个已经暂停的Activity
ActivityRecord mLastNoHistoryActivity = null;//最近一次没有历史记录的Activity
ActivityRecord mResumedActivity = null;//已经Resume的Activity
ActivityRecord mLastStartedActivity = null;//最近一次启动的Activity
ActivityRecord mTranslucentActivityWaiting = null;//传递给convertToTranslucent方法的最上层的Activity复制代码
这些特殊的状态都是ActivityRecord类型的,ActivityRecord用来记录一个Activity的全部信息。从栈的角度来讲(Activity任务栈是一个假想的模型),一个或多个ActivityRecord会组成一个TaskRecord,TaskRecord用来记录Activity的栈,而ActivityStack包含了一个或多个TaskRecord。
ActivityStack中维护了不少ArrayList,这些ArrayList中的元素类型主要有ActivityRecord和TaskRecord,其中TaskRecord用来记录Activity的Task。
ArrayList | 元素类型 | 说明 |
---|---|---|
mTaskHistory | TaskRecord | 全部没有被销毁的Task |
mLRUActivities | ActivityRecord | 正在运行的Activity,列表中的第一个条目是最近最少使用的元素 |
mNoAnimActivities | ActivityRecord | 不考虑转换动画的Activity |
mValidateAppTokens | TaskGroup | 用于与窗口管理器验证应用令牌 |
咱们知道Activity是由任务栈来进行管理的,不过任务栈是一个假想的模型,并不真实的存在。栈管理就是创建在这个假想模型之上的,有了栈管理,咱们能够对应用程序进行操做,应用能够复用自身应用中以及其余应用的Activity,节省了资源。好比咱们使用一款社交应用,这个应用的联系人详情界面提供了联系人的邮箱,当咱们点击邮箱时会跳到发送邮件的界面。
社交应用和系统Email中的Activity是处于不一样应用程序进程的,而有了栈管理,就能够把发送邮件界面放到社交应用中详情界面所在栈的栈顶,来作到跨进程操做。
为了更灵活的进行栈管理,Android系统提供了不少配置,下面分别对它们进行介绍。
Launch Mode都不会陌生,用于设定Activity的启动方式,不管是哪一种启动方式,所启动的Activity都会位于Activity栈的栈顶。有如下四种:
Intent中定义了不少了FLAG,其中有几个FLAG也能够设定Activity的启动方式,若是Launch Mode设定和FLAG设定的Activity的启动方式有冲突,则以FLAG设定的为准。
除了这三个FLAG,还有一些FLAG对咱们分析栈管理有些帮助。
接下来经过系统源码来查看FLAG的应用,在Android深刻四大组件(一)应用程序启动过程(后篇)中讲过,根Activity启动时会调用AMS的startActivity方法,通过层层调用会调用ActivityStarter的startActivityUnchecked方法,以下面的时序图所示。
frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {
setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
voiceInteractor);//1
computeLaunchingTaskFlags();//2
computeSourceStack();
mIntent.setFlags(mLaunchFlags);//3
...
}复制代码
注释1处用于初始化启动Activity的各类配置,在初始化前会重置各类配置再进行配置,这些配置包括:ActivityRecord、Intent、TaskRecord和LaunchFlags(启动的FLAG)等等。注释2处的computeLaunchingTaskFlags方法用于计算出启动的FLAG,并将计算的值赋值给mLaunchFlags。在注释3处将mLaunchFlags设置给Intent,达到设定Activity的启动方式的目的。接着来查看computeLaunchingTaskFlags方法。
frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java
private void computeLaunchingTaskFlags() {
...
if (mInTask == null) {//1
if (mSourceRecord == null) {//2
if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0 && mInTask == null) {//3
Slog.w(TAG, "startActivity called from non-Activity context; forcing " +
"Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
}
} else if (mSourceRecord.launchMode == LAUNCH_SINGLE_INSTANCE) {//4
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
} else if (mLaunchSingleInstance || mLaunchSingleTask) {//5
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
}
}
}复制代码
计算启动的FLAG的逻辑比较复杂,这里只截取了一小部分,注释1处的TaskRecord类型的mInTask为null时,说明Activity要加入的栈不存在。所以,这一小段代码主要解决的问题就是Activity要加入的栈不存在时如何计算出启动的FLAG。注释2处,ActivityRecord类型的mSourceRecord用于描述“初始Activity”,什么是“初始Activity”呢?好比ActivityA启动了ActivityB,ActivityA就是初始Activity。同时知足注释2和注释3的条件则须要建立一个新栈。注释4处,若是“初始Activity”所在的栈只容许有一个Activity实例,则也须要建立一个新栈。注释5处,若是Launch Mode设置了singleTask或singleInstance,则也要建立一个新栈。
咱们能够在AndroidManifest.xml设置android:taskAffinity,用来指定Activity但愿归属的栈, 默认状况下,同一个应用程序的全部的Activity都有着相同的taskAffinity。
taskAffinity在下面两种状况时会产生效果。
接着经过系统源码来查看taskAffinity的应用。ActivityStackSupervisor的findTaskLocked方法用于找到Activity最匹配的栈,最终会调用ActivityStack的findTaskLocked方法。
frameworks/base/services/core/java/com/android/server/am/ActivityStack.java
void findTaskLocked(ActivityRecord target, FindTaskResult result) {
...
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {//1
final TaskRecord task = mTaskHistory.get(taskNdx);//2
...
else if (!isDocument && !taskIsDocument
&& result.r == null && task.canMatchRootAffinity()) {
if (task.rootAffinity.equals(target.taskAffinity)) {//3
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching affinity candidate!");
result.r = r;
result.matchedByRootAffinity = true;
}
} else if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Not a match: " + task);
}
}复制代码
这个方法的逻辑比较复杂,这里截取了和taskAffinity相关的部分。注释1处遍历mTaskHistory列表,列表的元素为TaskRecord,
用于存储没有被销毁的Task。注释2处获得某一个Task的信息。注释3处将Task的rootAffinity(初始的taskAffinity)和目标Activity的taskAffinity作对比,若是相同,则将FindTaskResult的matchedByRootAffinity 属性设置为true,说明找到了匹配的Task。
参考资料
《深刻理解Android卷二》
《深刻理解Android内核设计思想》第二版
《Android开发艺术探索》
ActivityRecord、TaskRecord、ActivityStack
欢迎关注个人微信公众号,第一时间得到博客更新提醒,以及更多成体系的Android相关原创技术干货。
扫一扫下方二维码或者长按识别二维码,便可关注。