| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 开发测试 -> android R版本AppTransition动效源码分析 -> 正文阅读 |
|
[开发测试]android R版本AppTransition动效源码分析 |
????????AppTransition代表activity组件的切换过程,启动或是退出activity都会执行AppTransition,Android系统定义了多达十几种应用的transition类型,这些类型定义具体可参考WindowManager类。本文以TRANSIT_TASK_OPEN类型为例,场景以桌面点击图库冷启动为例。 以下文中AppTransition相关日志均需要执行命令开启输出到applogcat之中,正式商用版本也都可以以此方式打开: adb shell wm logging enable-text WM_DEBUG_APP_TRANSITIONS?WM_DEBUG_REMOTE_ANIMATIONS 其中,WM_DEBUG_APP_TRANSITIONS代表开启的是AppTransition相关日志;WM_DEBUG_REMOTE_ANIMATIONS表示开启的是RemoteAnimation相关的日志,桌面打开动效使用的就是RemoteAnimation。 一、冷启动跳转新应用 1、prepareAppTransition准备阶段 ? ? ? ? 在startActivity阶段会调用DisplayContent.prepareAppTransition去设置AppTransition类型为TRANSIT_TASK_OPEN,执行的是图中reusedTask为空分支。 09-08 09:42:05.169 ?1479 ?5339 I ActivityTaskManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.wtf.gallery3d/.app.MainActivity bnds=[48,1681][294,1992] (has extras)} from uid 10100 Prepare app transition日志中的transit是打算要设置的新transit,mNextAppTransition是当前已经存在的transit。 prepareAppTransition流程图如下: 该函数功能如下: 1)设置mNextAppTransition表明要执行的activity组件切换类型,设置值(非TRANSIT_UNSET值)后使得AppTransition.isTransitionSet()返回true表面已经设置了AppTransition。 2)该函数若重复执行,按其内部逻辑存在覆盖和不覆盖两种场景:覆盖场景常见的比如TRANSIT_TASK_OPEN替换掉TRANSIT_TASK_CLOSE、TRANSIT_ACTIVITY_OPEN 替换掉TRANSIT_ACTIVITY_CLOSE,也就是常说的open activity和open task的优先级要高于close activity和close task;不覆盖场景比如热启应用复用栈时会出现activityPaused阶段执行到resumeTop去设置TRANSIT_TASK_OPEN尝试替换掉startActivity阶段设置的TRANSIT_TASK_TO_FRONT,但不会被替换成功。 3)执行AppTransition.prepare()函数设置mAppTransitionState为APP_STATE_IDLE,即设置AppTransition的状态为IDLE空闲态,因为只有空闲状态才能执行下一个即将要执行的AppTransition。 完成这一步表明App Transition准备完成,但离动画执行还有十万八千里。 ? ? ? ? 其实在activityPaused阶段去resumeTop时仍然会触发一次设置TRANSIT_TASK_OPEN,代码和日志如下: 09-08 09:42:05.191 ?1479 ?1495 V WindowManager: Prepare app transition: transit=TRANSIT_TASK_OPEN mNextAppTransition=TRANSIT_TASK_OPEN alwaysKeepCurrent=false displayId=0 Callers=com.android.server.wm.DisplayContent.prepareAppTransition:5168 com.android.server.wm.DisplayContent.prepareAppTransition:5162 com.android.server.wm.ActivityStack.resumeTopActivityInnerLocked:2059 com.android.server.wm.ActivityStack.resumeTopActivityUncheckedLocked:1710 com.android.server.wm.RootWindowContainer.resumeFocusedStacksTopActivities:2478 activityPaused阶段的resumeTop设置动效类型为TRANSIT_TASK_OPEN,针对startActivity场景其实该处设置无效,因为之前startActivity流程已经设置过,但是对于back键等途径触发的resumeTop场景的设置仍然有效。? 2、setVisibility阶段 ? ? ? ? ActivityRecord.setVisibility函数的主要功能是把设置true的ActivityRecord加到DisplayContent.mOpeningApps列表,把设置false的ActivityRecord加到DisplayContent.mClosingApps列表,该函数在每次启动页面(不论热启冷起)的整个过程中可能涉及多次调用,是可重入的,且在执行DisplayContent.executeAppTransition之前都不会真正的commitVisibility(GOOD TO GO阶段才会真正执行),仅仅是填充mOpeningApps和mClosingApps,目的是在GOOD TO GO真正做动效时有目标的退场和入场应用去执行动效。 ? ? ? ? 冷起时首次触发桌面加到mClosingApps、图库加到mOpeningApps是由activityPaused阶段的以下函数触发: 之前分析应用启动时曾说过,冷起新栈,由completePaused结束的那次ensureActivitiesVisible来触发将桌面makeInvisible进而触发ActivityRecord.setVisibility(false)加到mClosingApps、将图库makeVisibleAndRestartIfNeeded进而触发ActivityRecord.setVisibility(true)加到mOpeningApps。 图库ensure执行的分支: 09-08 09:42:05.192 ?1479 ?1495 V WindowManager: setAppVisibility(Token{5817814 ActivityRecord{7ddd3b9 u0 com.wtf.gallery3d/.app.MainActivity t5931}}, visible=true): mNextAppTransition=TRANSIT_TASK_OPEN visible=false mVisibleRequested=false Callers=com.android.server.wm.ActivityRecord.setVisibility:4405 com.android.server.wm.EnsureActivitiesVisibleHelper.makeVisibleAndRestartIfNeeded:223 com.android.server.wm.EnsureActivitiesVisibleHelper.setActivityVisibilityState:155 com.android.server.wm.EnsureActivitiesVisibleHelper.lambda$Bbb3nMFa3F8er_OBuKA7-SpeSKo:0 com.android.server.wm.-$$Lambda$EnsureActivitiesVisibleHelper$Bbb3nMFa3F8er_OBuKA7-SpeSKo.accept:12 com.android.internal.util.function.pooled.PooledLambdaImpl.doInvoke:307? 桌面ensure执行的分支: 虽然activityPaused中的completePaused可以最终触发到桌面和图库的ActivityRecord.setVisibility,但由于是冷起栈,realStartActivityLocked阶段仍然可以触发要启动的图库执行一次ActivityRecord.setVisibility(true),且该次才是最关键的一次,日志如下: 09-08 09:42:05.235 ?1479 ?4303 V WindowManager: setAppVisibility(Token{5817814 ActivityRecord{7ddd3b9 u0 com.wtf.gallery3d/.app.MainActivity t5931}}, visible=true): mNextAppTransition=TRANSIT_TASK_OPEN visible=false mVisibleRequested=true Callers=com.android.server.wm.ActivityRecord.setVisibility:4405 com.android.server.wm.ActivityStackSupervisor.realStartActivityLocked:881 com.android.server.wm.RootWindowContainer.startActivityForAttachedApplicationIfNeeded:2139 com.android.server.wm.RootWindowContainer.lambda$5fbF65VSmaJkPHxEhceOGTat7JE:0 com.android.server.wm.-$$Lambda$RootWindowContainer$5fbF65VSmaJkPHxEhceOGTat7JE.apply:8 com.android.internal.util.function.pooled.PooledLambdaImpl.doInvoke:315 而无论是冷启还是热启,都会执行ActivityRecord.completeResumeLocked,该函数同样会把要resume的页面执行ActivityRecord.setVisibility(true),虽然对于冷起场景此次调用属于多余的操作,但是对于热启复用栈场景该处很关键,因为热启场景不会调用realStartActivityLocked但是仍然会调用completeResumeLocked,冷启场景日志如下: 09-08 09:42:05.239 ?1479 ?4303 V WindowManager: setAppVisibility(Token{5817814 ActivityRecord{7ddd3b9 u0 com.wtf.gallery3d/.app.MainActivity t5931}}, visible=true): mNextAppTransition=TRANSIT_TASK_OPEN visible=false mVisibleRequested=true Callers=com.android.server.wm.ActivityRecord.setVisibility:4405 com.android.server.wm.ActivityRecord.completeResumeLocked:5373 com.android.server.wm.ActivityStack.minimalResumeActivityLocked:1028 com.android.server.wm.ActivityStackSupervisor.realStartActivityLocked:1020 com.android.server.wm.RootWindowContainer.startActivityForAttachedApplicationIfNeeded:2139 com.android.server.wm.RootWindowContainer.lambda$5fbF65VSmaJkPHxEhceOGTat7JE:0 3、executeAppTransition阶段 ? ? ? ? 无论是冷启还是热启,都是由ActivityRecord.completeResumeLocked阶段触发的DisplayContent.executeAppTransition来最终执行AppTransition,当然此处仅是执行AppTransition,并不代表能一定执行动效,因为动效的执行需要依赖mOpeningApps中的应用绘制完成才能够执行。DisplayContent.executeAppTransition功能如下: 1)首先调用AppTransition.isTransitionSet()判断是否有设置transit,若未设置则该函数不产生任何作用。 2)调用AppTransition.setReady()函数将mAppTransitionState从APP_STATE_IDLE状态切换到APP_STATE_READY,只有ready之后才有可能触发GOOD TO GO流程,ready之前就算窗口绘制完毕(假设有此异常流程)也无法执行到GOOD TO GO。 09-08 09:42:05.240 ?1479 ?4303 W WindowManager: Execute app transition: mNextAppTransition=TRANSIT_TASK_OPEN, displayId: 0 Callers=com.android.server.wm.RootWindowContainer.executeAppTransitionForAllDisplay:2399 com.android.server.wm.ActivityStackSupervisor.reportResumedActivityLocked:2092 com.android.server.wm.ActivityRecord.completeResumeLocked:5402 com.android.server.wm.ActivityStack.minimalResumeActivityLocked:1028 com.android.server.wm.ActivityStackSupervisor.realStartActivityLocked:1020 4、GOOD TO GO阶段 ? ? ? ? 执行完executeAppTransition并不一定立马就能触发动效的执行,需要等要打开的ActivityRecord窗口绘制完成(有starting window的只需要starting window绘制完成,不需要等到主窗口绘制完成),才能触发GOOD TO GO真正执行动画。GOOD TO GO执行动画流程如下: 在wms每次触发performSurfacePlacement刷新surface时,都会尝试检查下DisplayContent是否有设置了动画且满足Ready状态、要做动画的应用是否绘制完成,如果这些条件都满足则进入GOOD TO GO阶段去apply动效真正执行动效。 二、热启动跳转新应用 1、prepareAppTransition准备阶段 ? ? ? ? 在startActivity阶段会调用DisplayContent.prepareAppTransition去设置AppTransition类型为TRANSIT_TASK_TO_FRONT,执行的是前文中startActivity流程的reusedTask非空分支。 09-08 09:42:07.711 ?1479 ?4064 I ActivityTaskManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.wtf.gallery3d/.app.MainActivity bnds=[48,1681][294,1992] mCallingUid=10100} from uid 10100 and from pid 3367 在activityPaused阶段去resumeTop时仍然如冷起场景一样都会执行重新设置transit的动作: 09-08 09:42:07.741 ?1479 ?3574 V WindowManager: Prepare app transition: transit=TRANSIT_TASK_OPEN mNextAppTransition=TRANSIT_TASK_TO_FRONT alwaysKeepCurrent=false displayId=0 Callers=com.android.server.wm.DisplayContent.prepareAppTransition:5168 com.android.server.wm.DisplayContent.prepareAppTransition:5162 com.android.server.wm.ActivityStack.resumeTopActivityInnerLocked:2059 com.android.server.wm.ActivityStack.resumeTopActivityUncheckedLocked:1710 com.android.server.wm.RootWindowContainer.resumeFocusedStacksTopActivities:2478? 2、setVisibility阶段 ? ? ? ? 热启场景在activityPaused阶段执行resumeTop时就会把pause成功的桌面执行setVisibility(false)加到mClosingApps、把要resume的图库执行setVisibility(true)加到mOpeningApps,而不需要依赖completePaused结束的那次ensureActivitiesVisible。 resumeTop时图库被setVisibility(true): 09-08 09:42:07.742 ?1479 ?3574 V WindowManager: setAppVisibility(Token{5817814 ActivityRecord{7ddd3b9 u0 com.wtf.gallery3d/.app.MainActivity t5931}}, visible=true): mNextAppTransition=TRANSIT_TASK_TO_FRONT visible=false mVisibleRequested=false Callers=com.android.server.wm.ActivityRecord.setVisibility:4405 com.android.server.wm.ActivityStack.resumeTopActivityInnerLocked:2141 com.android.server.wm.ActivityStack.resumeTopActivityUncheckedLocked:1710 com.android.server.wm.RootWindowContainer.resumeFocusedStacksTopActivities:2478 com.android.server.wm.ActivityStack.completePauseLocked:1370 com.android.server.wm.ActivityRecord.activityPaused:5475? resumeTop时桌面被setVisibility(false): 09-08 09:42:07.745 ?1479 ?3574 V WindowManager: setAppVisibility(Token{6d196ad ActivityRecord{e45e1e5 u0 com.wtf.launcher/.Launcher t5815}}, visible=false): mNextAppTransition=TRANSIT_TASK_TO_FRONT visible=true mVisibleRequested=true Callers=com.android.server.wm.ActivityRecord.setVisibility:4405 com.android.server.wm.ActivityRecord.makeInvisible:5168 com.android.server.wm.EnsureActivitiesVisibleHelper.setActivityVisibilityState:182 com.android.server.wm.EnsureActivitiesVisibleHelper.lambda$Bbb3nMFa3F8er_OBuKA7-SpeSKo:0 com.android.server.wm.-$$Lambda$EnsureActivitiesVisibleHelper$Bbb3nMFa3F8er_OBuKA7-SpeSKo.accept:12 com.android.internal.util.function.pooled.PooledLambdaImpl.doInvoke:307 热启场景resumeTop最终也会执行ActivityRecord.completeResumeLocked,同样还会重复执行一次setAppVisibility,可以认为热启场景,completeResumeLocked引发的此次setAppVisibility是最关键的一次。 09-08 09:42:07.746 ?1479 ?3574 V WindowManager: setAppVisibility(Token{5817814 ActivityRecord{7ddd3b9 u0 com.wtf.gallery3d/.app.MainActivity t5931}}, visible=true): mNextAppTransition=TRANSIT_TASK_TO_FRONT visible=false mVisibleRequested=true Callers=com.android.server.wm.ActivityRecord.setVisibility:4405 com.android.server.wm.ActivityRecord.completeResumeLocked:5373 com.android.server.wm.ActivityStack.resumeTopActivityInnerLocked:2273 com.android.server.wm.ActivityStack.resumeTopActivityUncheckedLocked:1710 com.android.server.wm.RootWindowContainer.resumeFocusedStacksTopActivities:2478 com.android.server.wm.ActivityStack.completePauseLocked:1370? 3、executeAppTransition阶段 ? ? ? ? 无论是冷启还是热启,都是由ActivityRecord.completeResumeLocked阶段触发的DisplayContent.executeAppTransition来最终执行AppTransition,不同的是热启阶段触发的completeResumeLocked不是由realStartActivityLocked和minimalResumeActivityLocked触发,而是由resumeTop直接触发。 09-08 09:42:07.746 ?1479 ?3574 W WindowManager: Execute app transition: mNextAppTransition=TRANSIT_TASK_TO_FRONT, displayId: 0 Callers=com.android.server.wm.RootWindowContainer.executeAppTransitionForAllDisplay:2399 com.android.server.wm.ActivityStackSupervisor.reportResumedActivityLocked:2092 com.android.server.wm.ActivityRecord.completeResumeLocked:5402 com.android.server.wm.ActivityStack.resumeTopActivityInnerLocked:2273 com.android.server.wm.ActivityStack.resumeTopActivityUncheckedLocked:1710 4、GOOD TO GO阶段 ? ? ? ? 此阶段与冷启场景动效执行流程一样,不再赘述。 |
|
开发测试 最新文章 |
pytest系列——allure之生成测试报告(Wind |
某大厂软件测试岗一面笔试题+二面问答题面试 |
iperf 学习笔记 |
关于Python中使用selenium八大定位方法 |
【软件测试】为什么提升不了?8年测试总结再 |
软件测试复习 |
PHP笔记-Smarty模板引擎的使用 |
C++Test使用入门 |
【Java】单元测试 |
Net core 3.x 获取客户端地址 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/18 0:48:07- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |