一、概念
1、Task
Task是指将相关的Activity组合到一起,以Activity Stack的方式进行管理。从用户体验上讲,一个“应用程序”就是一个Task(默认情况),但是从根本上讲,一个Task是可以有一个或多个Android Application组成的。
Task表示一个任务,每一个Task 会有一个ID作为唯一标识。一个进程(程序)有一个默认的task affinity,默认为包名,也可以多个程序指定同一个TaskAffinity。Activity的启动会进入到对应的Task当中或者重新启动一个新的Task。Android源码里面有一个TaskRecord类,该类的一个实例就对应着一个Task。
一组Task以链表的方式相互连接,每一个Task会有一个前驱任务点和后继任务点,以此来管理Task的编辑和查找。ActivityStack外部以链表的形式管理Task,Task内部以后进先出的历史顺序方式管理Activity。
下面的Task的一段源码,我们可以看到它的主要结构:
final class TaskRecord {
private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM;
......
static final String ATTR_TASKID = "task_id";
......
//任务的前驱节点
TaskRecord mPrevAffiliate; // previous task in affiliated chain.
int mPrevAffiliateTaskId = INVALID_TASK_ID; // previous id for persistence.
//该任务的后继节点
TaskRecord mNextAffiliate; // next task in affiliated chain.
int mNextAffiliateTaskId = INVALID_TASK_ID; // next id for persistence.
......
/** List of all activities in the task arranged in history order */
//该Task下的Activity,以后进先出的方式存放
final ArrayList<ActivityRecord> mActivities;
/** 当前的Activity栈 */
ActivityStack stack;
}
2、ActivityStack
Stack表示任务栈,任务栈是以Task为基本单位的。一般我们的程序切换就是Task的切换,一个程序从后台任务栈到前台任务栈,是整个任务栈的移动,而不仅仅是Activity的移动,在任务栈移动之后,再按照LaunchModel的规则对Activity进行操作。与Stack相对应的有Android源码里面的ActivityStack类。一般来说,我们的应用程序都在一个单例的ActivityStack当中。
ActivityStack里面还维护着一个Activity的LRU运行列表,按照最近访问且正在运行的Activity排列。
/**
* 单列的Activity栈
* State and management of a single stack of activities.
*/
final class ActivityStack {
/**
* List of running activities, sorted by recent usage.
* The first entry in the list is the least recently used.
* It contains HistoryRecord objects.
*/
final ArrayList<ActivityRecord> mLRUActivities = new ArrayList<>();
}
这个是使用adb shell dumpsys activity 查看Activity栈信息的时候打印出来的一个LRU的Activity列表。
//LRU的方式管理的正在运行的Activity列表
Running activities (most recent first):
//#276表示该Task的TaskID; A = com.example.malingyi.testtask1 表示该Task的TaskAffinity值,sz = 2表示该Task内部Activity的数量
TaskRecord{
51e812a #276 A=com.example.malingyi.testtask1 U=0 sz=2}
Run #3: ActivityRecord{c5e365e u0 com.example.malingyi.testtask1/.ActivityA t276}
TaskRecord{
56c2a15 #277 A=com.example.malingyi.testtask2 U=0 sz=2}
Run #2: ActivityRecord{e3bed35 u0 com.example.malingyi.testtask2/.ActivityB t277}
Run #1: ActivityRecord{532f30e u0 com.example.malingyi.testtask2/.MainActivity t277}
TaskRecord{
51e812a #276 A=com.example.malingyi.testtask1 U=0 sz=2}
Run #0: ActivityRecord{e5c7c57 u0 com.example.malingyi.testtask1/.MainActivity t276}
//前台正在运行的Activity
mResumedActivity: ActivityRecord{
3a73c94 u0 com.example.malingyi.testtask2/.ActivityA t253}
3、ActivityRecord、ProcessRecord
ActivityRecord:代表着一个在Task里面正在活动的Acitivty的信息记录。
/**
* An entry in the history stack, representing an activity.
*/
final class ActivityRecord {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityRecord" : TAG_AM;
...
final ActivityManagerService service; // owner
final IApplicationToken.Stub appToken; // window manager token
final ActivityInfo info; // all about me
final ApplicationInfo appInfo; // information about activity's app
final int userId; // Which user is this running for?
final Intent intent; // the original intent that generated us
final ComponentName realActivity; // the intent component, or target of an alias.
...
//包的名称
final String packageName; // the package implementing intent's component
//进程的名称
final String processName; // process where this component wants to run
//Task的名称
final String taskAffinity; // as per ActivityInfo.taskAffinity
//Activity所在的任务栈
TaskRecord task; // the task this is in.
...
}
ProcessRecord:当前运行的进程信息,描述了该进程的所有信息。
/**
* Full information about a particular process that
* is currently running.
*/
final class ProcessRecord {
...
}
二、任务栈的切换演示:
假设:
有两个程序:App1、App2,包名为:App1 = com.example.malingyi.testtask1 App2 = com.example.malingyi.testtask1;
ActivityA属于App1、ActivityB属于App2;两个App都有MainActivity作为启动入口。
情况一:单一Task&默认的启动模式下,App切换时的Activity栈情况
启动模式:
ActivityA:standard
ActivityB:standard
App1、App2:MainActivity:standard
TaskAffinity:
都是默认情况下的TaskAffinity(包名)
初始化启动顺序:
Step1:启动App1:MainActivity——>ActivityA ;
Step2:启动App2:MainActivity——>ActivityB;
**栈顶Activity:**ActivityB
Activity栈:
App1.MainActivity——>App1.ActivityA——>App2.MainActivity——>App2.ActivityB
初始任务栈信息如下:
Stack #8:
Task id #282 //App2的Task栈
TaskRecord{cde1503 #282 A=com.example.malingyi.testtask2 U=0 sz=2} //Task信息
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.example.malingyi.testtask2/.MainActivity bnds=[236,972][356,1092] (has extras) }
Hist #1: ActivityRecord{218b549 u0 com.example.malingyi.testtask2/.ActivityB t282}//Activity信息
Intent { cmp=com.example.malingyi.testtask2/.ActivityB }
ProcessRecord{
77bd789 3202:com.example.malingyi.testtask2/u0a63}
Hist #0: ActivityRecord{735919e u0 com.example.malingyi.testtask2/.MainActivity t282}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.example.malingyi.testtask2/.MainActivity bnds=[236,972][356,1092] (has extras) }
ProcessRecord{
77bd789 3202:com.example.malingyi.testtask2/u0a63} //进程信息
Task id #281。//App1的Task栈
TaskRecord{
8480c80 #281 A=com.example.malingyi.testtask1 U=0 sz=2} //Task信息
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.example.malingyi.testtask1/.MainActivity bnds=[60,972][180,1092] (has extras) }
Hist #1: ActivityRecord{66d10ee u0 com.example.malingyi.testtask1/.ActivityA t281}//Activity信息
Intent { cmp=com.example.malingyi.testtask1/.ActivityA }
ProcessRecord{
57c82b9 3305:com.example.malingyi.testtask1/u0a60}
Hist #0: ActivityRecord{157ed43 u0 com.example.malingyi.testtask1/.MainActivity t281}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.example.malingyi.testtask1/.MainActivity bnds=[60,972][180,1092] (has extras) }
ProcessRecord{
57c82b9 3305:com.example.malingyi.testtask1/u0a60} //进程信息
(1)从App2.ActivityB启动App1.ActivityA
切换后任务栈:
Stack #8:
Task id #282 //栈顶还是App2的Task,APP.ActivityA进入了App2的Task栈中。
TaskRecord{cde1503 #282 A=com.example.malingyi.testtask2 U=0 sz=3}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=