Android源码分析:Activity启动流程Task相关分析
Activity的启动分析,很大一块需要了解的是Activity的Task管理,以及启动过程中Task的决策,在之前分析启动流程中,关于Task处理的部分,我这里是简化掉了很多的,今天再来分析一下。 入口与计算启动参数 在之前分析Activity的启动中,已经看到了关于处理Task的代码是在ActivityStart当中的startActivityInner方法当中,这个方法有不少入参,先捋一遍: resultTo为调用的Activity的mToken(IBinder) ActivityRecord r, //新创建的Record,包含calling信息和要打开的ActivityInfo等 ActivityRecord sourceRecord, //resultTo不为空的时候才会去使用`ActivityRecord isInAnyTask`读取 IvoiceInteractionSession voiceSession, //startVoiceActivity的时候才会传 IvoiceInteractor voiceInteractor, //同上,一般为系统的语音助手界面 int startFlags, //客户端传过来的startFlags一般为0 boolean doResume, //是否需要去resume activity,对于启动Activity场景总是为true ActivityOptions options, //Activity启动的一些参数,页面跳转动画等 Task inTask, //一般为通过AppTaskImpl启动Activity才会设置值,正常app启动不存在 TaskFragment inTaskFragment, //同上,一般情况为空 int balCode, //Activity后台启动的许可Code,默认为BAL_ALLOW_DEFAULT NeededGrants intentGrants //Intent访问权限授权 有了所有的入参可以看看computeLaunchingTaskFlags,对于普通应用mInTask为空,mSourceRecord不为空,关注这个方法内的如下代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 if (mInTask == null) { if (mSourceRecord == null) { if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0 && mInTask == null) { //如果获取不到启动来源的ActivityRecord,且当前要启动的Activity还没有设置NEW_TASK flag,则给他添加 mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK; } } else if (mSourceRecord.launchMode == LAUNCH_SINGLE_INSTANCE) { //如果来源ActivityRecord是SINGLE INSTANCE,也就是说它是自己独立的任务栈,新启动Activity必须设置NEW_TASK mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK; } else if (isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) { //如果新启动的Activity是SingleInstance或者SingleTask,也要添加NEW_TASK flag mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK; } } if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0 && ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0 || mSourceRecord == null)) { //如果要启动的Activity设置了分屏的FLAG,但是却没有设置NEW——FLAG或者没有源ActivityRecord,这个时候就需要忽略掉分屏的这个FLAG mLaunchFlags &= ~FLAG_ACTIVITY_LAUNCH_ADJACENT; } 简化版本的流程图如下: 获取当前的顶部Task: getFocusedRootTask 以上是针对LaunchFlag的一部分处理,但并不是全部,暂时继续往后看。随后就是获取task 1 2 3 final Task prevTopRootTask = mPreferredTaskDisplayArea.getFocusedRootTask(); final Task prevTopTask = prevTopRootTask != null ? prevTopRootTask.getTopLeafTask() : null; final Task reusedTask = getReusableTask(); 首先看这个mPreferredTaskDisplayArea,这个表示倾向的Activity显示的TaskDisplay,它的赋值是在前面的setInitialState方法中: 1 2 3 4 5 mSupervisor.getLaunchParamsController().calculate(inTask, r.info.windowLayout, r, sourceRecord, options, mRequest, PHASE_DISPLAY, mLaunchParams); mPreferredTaskDisplayArea = mLaunchParams.hasPreferredTaskDisplayArea() ? mLaunchParams.mPreferredTaskDisplayArea : mRootWindowContainer.getDefaultTaskDisplayArea(); 我们这里就以它是拿的DefaultTaskDisplayArea为例来分析,继续就是看它的getFocusedRootTask,看代码之前先看看这些类的关系图,之前画过Task,WindowContainer相关的,但是还不够全,这里再补充完整一点。 classDiagram class ConfigurationContainer { <<abstract>> } class WindowContainer { List<WindowContainer> mChildren } class TaskFragment class Task class ActivityRecord { Task task TaskDisplayArea mHandoverTaskDisplayArea } ConfigurationContainer <|--WindowContainer WindowContainer <|-- TaskFragment TaskFragment <|--Task WindowContainer <|--RootWindowContainer WindowContainer <|-- DisplayArea DisplayArea <|-- TaskDisplayArea WindowContainer"0..*" <-- "1*"WindowContainer WindowContainer <|-- WindowToken WindowToken <|--ActivityRecord ActivityRecord --> Task ActivityRecord --> TaskDisplayArea当然WindowContainer的子类远不止这些,包括WindowState等等都是它的子类,但是暂时不需要讨论他们,这里暂时先不列出来了。 我们还是先看getFocusedRootTask方法的源码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 Task getFocusedRootTask() { if (mPreferredTopFocusableRootTask != null) { return mPreferredTopFocusableRootTask; } for (int i = mChildren.size() - 1; i >= 0; --i) { final WindowContainer child = mChildren.get(i); if (child.asTaskDisplayArea() != null) { final Task rootTask = child.asTaskDisplayArea().getFocusedRootTask(); if (rootTask != null) { return rootTask; } continue; } final Task rootTask = mChildren.get(i).asTask(); if (rootTask.isFocusableAndVisible()) { return rootTask; } } return null; } 如果说当前的TaskDisplayArea中,preferredTopFocusableRoot存在就会直接使用,这个会在postionChildTaskAt的时候,如果child放置到顶部,并且它是可获得焦点的,会把他赋值给这个preferredTopFocusableRoot。 我们这里先看它为空的情况。如果它为空,这回到树状结构中查找,遍历树节点如果也是TaskDisplayArea,则会 看他们的focusedRootTask是否存在,如果就返回。如果节点是Task,就会检查这个Task是否为可获得焦点并且可见的,则返回它。否则就返回空。因为我们当前已经打了Activity,这里一般是可以获得值的。 如果拿到了prevTopRootTask,就会去调用getTopLeafTask去获取叶子节点的Task,代码如下: 1 2 3 4 5 6 7 8 public Task getTopLeafTask() { for (int i = mChildren.size() - 1; i >= 0; --i) { //从大数开始遍历 final Task child = mChildren.get(i).asTask(); if (child == null) continue; //如果不是Task就跳过 return child.getTopLeafTask(); //继续看它的子节点 } return this; //没有孩子节点,那就是一个叶子节点 } 以上是获取叶子节点的代码,典型的树的遍历代码。到目前是拿的当前在展示的页面的任务栈。 获取可复用的Task:getReusableTask 而之后的getReusableTask则是获取可以使用的任务Task: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 private Task getReusableTask() { //一般是从最近任务打开的页面才会执行这里,我们可以跳过 if (mOptions != null && mOptions.getLaunchTaskId() != INVALID_TASK_ID) { Task launchTask = mRootWin
以上内容来自博客订阅源,版权归原作者。关注作者后可以在 关注列表 第一时间查看作者文章。

登录后,加入这场讨论。
登录参与