![](https://file.jishuzhan.net/article/1795108592412528641/132d2e8330d5046aaa97ddb0cba741a0.webp)
这一节的内容涉及WMCore以及WMShell,主要是启动Transition。
回到ActivityStarter.startActivityUnchecked方法:
![](https://file.jishuzhan.net/article/1795108592412528641/8d0bbdf74e462055bb80d243e2bae0f6.webp)
看下最后启动Transition的部分,在ActivityStarter.handleStartResult中:
![](https://file.jishuzhan.net/article/1795108592412528641/64df2245ab909f6203990f58e0123adb.webp)
只关注我们要关注的部分。
首先是如果这里的局部变量isStarted为true,就说明这个ActivityRecord是新建的,因此调用TransitionController.collectExistenceChange方法:
![](https://file.jishuzhan.net/article/1795108592412528641/7c7208733b0f02fb4d1818eb8b11b903.webp)
将从正在收集的这个Transition的mChanges中找到这个新建的ActivityRecord的ChangeInfo对象,将其成员变量mExistenceChanged置为true,表示这个WindowContainer在本次改变前后的存在性发生了变化,即从无到有(OPEN),或者从有到无(CLOSE)。
再回到ActivityStarter.handleStartResult,根据我们的分析流程,这里传入的newTransition不为空,所以所以这里继续调用的是TransitionController.requestStartTransition方法。
1 WMCore部分 ------ TransitionController.requestStartTransition
![](https://file.jishuzhan.net/article/1795108592412528641/1f9faa0b230b60260b35c0bc6626b031.webp)
从注释可知,该方法用来向Player(WMShell)端创建一个Transition,但是不要启动。
该方法的内容主要为:
1)、创建一个TransitionRequestInfo对象:
![](https://file.jishuzhan.net/article/1795108592412528641/af9598298c14d6415d17c7a61a2e0793.webp)
TransitionRequestInfo是继承了Parcelable的类,用来将WMCore端的一些信息进行封装,发送给WMShell端。
比如这里的triggerTask,如果不为空,就包含了那个生命周期变化(start或者finish)导致本次Transition发生的那个Activity对应的Task的信息。
2)、调用成员变量mTransitionPlayer的requestStartTransition方法,先看这个成员变量mTransitionPlayer:
![](https://file.jishuzhan.net/article/1795108592412528641/8bf899a121eb079507b9aef4f4962b2c.webp)
类型为ITransitionPlayer,它的定义为:
![](https://file.jishuzhan.net/article/1795108592412528641/bd1f9dbd1e2e3e65c8cbf858deaa9e06.webp)
大概翻译为:
该接口由WMShell实现,用于启动和播放过渡动画。和IWindowOrganizerController一起使用的流程如下:
- WMCore启动一个Activity并调用requestStartTransition方法。
- 这个TransitionPlayer的实现执行相应操作,然后调用IWindowOrganizerController的startTransition方法,告诉WMCore正式开始(在此之前,WMCore将收集Transition中的所有更改,但不会认为Transition已准备好进行动画)。
- 一旦Transition中所有收集的更改都完成绘制,WMCore将调用onTransitionReady方法,在这里委托实际的动画。
- 一旦这个TransitionPlayer的实现完成动画,它通过IWindowOrganizerController的finishTransition方法通知WMCore。此时,ITransitionPlayer的责任结束。
ITransitionPlayer接口中包含两个方法:
- onTransitionReady: 当Transition的所有参与者准备好进行动画时调用。作为对startTransition方法的响应。
- requestStartTransition: 当WMCore中的某些内容需要播放Transition时调用,例如在新Task中启动Activity时。
该注释已经解释的很清楚了,现在我们已经在WMCore端封装好需要传递的信息了,下一步就是调用ITransitionPlayer.requestStartTransition将这些信息发送到WMShell端,来通知那边创建一个Transition。
2 WMShell部分 ------ Transitions.requestStartTransition
从上面ITransitionPlayer的注释我们知道了ITransitionPlayer的实现端在WMShell,具体则是定义在Transitions中的TransitionPlayerImpl类:
![](https://file.jishuzhan.net/article/1795108592412528641/5ec7f24e6232d98683469e8b5dffb1d2.webp)
它实现了ITransitionPlayer中定义的两个方法接口,我们先分析requestStartTransition,后面等遇到的时候再分析onTransitionReady。
Transitions.requestStartTransition的内容为:
![](https://file.jishuzhan.net/article/1795108592412528641/ffac9b92aa09905166c5edecff3a1d48.webp)
1)、创建一个ActiveTransition对象:
![](https://file.jishuzhan.net/article/1795108592412528641/61a9d1bad69ebe0f361b7196609d5538.webp)
ActiveTransition中有一个IBinder类型的mToken成员,用来保存从WMCore中传来的Transition的token,那么可以认为WMCore端的Transition和WMShell端的ActiveTransition是一个一一对应的关系,这样也有助于理解TransitionController.requestStartTransition的注释:
"Asks the transition player (shell) to start a created but not yet started transition."
这里要player创建的transition并非Transition,而是ActiveTransition。
ActiveTransition中的其它成员变量也非常重要,不过现在我不打算全部说明,用到的时候再说吧。
2)、调用Transitions.mHandlers中的每一个TransitionHandler的handleRequest方法,来为这个刚刚创建的ActiveTransition找到一个后续走到Transitions.onTransitionReady时,执行动画的Transitions.TransitionHandler对象,并且添加到Transitions.mPendingTransitions中。后续走到Transitions.onTransitionReady的时候,再从Transitions.mPendingTransitions中拿需要执行动画的TransitionHandler对象。
Transitions的mHandlers成员变量是一个TransitionHandler类型的队列:
![](https://file.jishuzhan.net/article/1795108592412528641/1288676fe4281536b9572fa49eab6738.webp)
TransitionHandler表示可以处理一组过渡动画的接口:
![](https://file.jishuzhan.net/article/1795108592412528641/50980b08eca7dbd99746ab2472f952fc.webp)
该接口定义了以下方法:
- startAnimation: 开始一个过渡动画。如果handleRequest方法返回非空值,则始终调用此方法来处理特定Transition。否则,仅当之前没有其他handler处理Transition时才调用此方法。
- handleRequest: 可能处理startTransition请求。
- 等等...
开机SystemUI进程起来后,就会向Transitions.mHandlers中添加多个TransitionController的子类:
![](https://file.jishuzhan.net/article/1795108592412528641/8c38777c50c315de66047ba018ce2b23.webp)
从名字上也能看出这些TransitionController的子类对应的不同类型的Transition的动画。
3)、当创建了ActiveTransition后,下一步就是决定哪一个TransitionHandler来处理当前Transition,具体说来则是遍历Transitions.mHandlers,按照顺序对每一个TransitionHandler调用handleRequest方法,看哪一个子类可以处理这个Transition,比如我这里打印的log:
![](https://file.jishuzhan.net/article/1795108592412528641/cbc488e77bfea42239b72da4df72fa7e.webp)
如果找到了这么一个TransitionHandler对象,那么就把它保存在ActiveTransition.mHandler中,后续onTransitionReady流程会用。
4)、调用WIndowOrganizer.startTransition来启动一个已经创建的Transition,这最终会调用到WindowOrganizerController.startTransition,这就又回到WMCore的部分了,下一节再说。
5)、将WMCore传过来的Transition的token赋值给ActiveTransition.mToken。
6)、将这个创建的ActiveTransition对象添加到成员变量mPendingTransitions中:
![](https://file.jishuzhan.net/article/1795108592412528641/ef88d0bdda1c53cf1dbe130afc5c5772.webp)
成员变量mPendingTransitions是一个ActiveTransition的队列,用来保存那些已经启动,但是还没有就绪的Transition。
后续Transition就绪的时候,即onTransitionReady流程,就会从mPendingTransitions中拿ActiveTransition对象来执行动画。
3 WMCore部分 ------ Transition.start
直接看WindowOrganizerController.startTransition:
![](https://file.jishuzhan.net/article/1795108592412528641/401e1dd4892eedf4f8e5b915e285cb3f.webp)
从WMCore到WMShell再到WMCore,我们始终传递着IBinder类型的Transition对应的token,因此这里的Transition是不为null的。
因此只需要关注最后调用的Transition.start。
![](https://file.jishuzhan.net/article/1795108592412528641/d22455bcaa077b9e64760b467f6067f9.webp)
正式启动Transition,再次之前可以收集参与者,但是直到启动后Transition才会被视为就绪,即使所有的参与者都已经绘制完成。
1)、将Transition的状态置为STATE_STARTED,之前的状态为STATE_COLLECTING。
2)、调用Transition.applyReady。
![](https://file.jishuzhan.net/article/1795108592412528641/936dc5698d19bfeab9ed2f4d9e7c68b9.webp)
继续调用了BLASTSyncEngine.setReady方法:
![](https://file.jishuzhan.net/article/1795108592412528641/87131ac54426bc8e3728b70afc1b7a0f.webp)
最终调用的是SyncGroup.setReady方法:
![](https://file.jishuzhan.net/article/1795108592412528641/f977a9ee0663ed39c29264c5995b0c9b.webp)
重要的其实就那一句,即将SyncGroup的成员变量mReady设置为true,顺便可以调用WindowSurfacePlacer.requestTraversal,看看SyncGroup是否完成,即它里面的所有参与者是否已经准备就绪(绘制完成)。
mReady这个成员变量还是很重要的,只有被设置为true,系统才会去检查这个SyncGroup是否完成。
4 小结
启动Transition这一节的内容还是挺多的,大概总结一下:
1)、在WMCore侧,调用ITransitionPlayer.requestStartTransition切换到WMShell。
2)、在WMShell侧,创建一个Transitions.ActiveTransition对象,为其找到一个后续执行动画的Transitions.TransitionHandler对象,接着将该Transitions.ActiveTransition对象添加到Transitions.mPendingTransitions中,后续动画就绪的时候,就是从Transitions.mPendingTransitions中拿需要play的Transitions.ActiveTransition对象。
3)、回到WMCore侧,得知在WMShell侧创建了和当前Transition一一对应的ActiveTransition后,这个Transition的状态就从STATE_COLLECTING切换为STATE_STARTED,并且相应的SyncGroup的成员变量mReady也被设置为true。
启动Transition的流程再总结的简单一点,就是之前在WMCore这一侧不是创建了一个Transition对象嘛,现在需要在WMShell这一侧创建一个相应的ActiveTransition。一旦这个ActiveTransition创建完成了,WMShell再告知WMCore,WMCore就知道WMShell那边的前序工作已经完成了,那就把Transition标记为STATE_STARTED,SyncGroup标记为ready。后续Transition满足进入下一个阶段的条件了,再看SyncGroup是不是ready了,如果ready了,就说明WMShell那也有一个ActiveTransition了,Transition就可以进入下一个阶段了。
5 从WMShell发起Transition
之前分析的流程是WMCore先创建一个Transition,然后WMShell再创建一个ActiveTransition。
还有一种方式是WMShell先创建ActiveTransition,然后WMCore再创建Transition,即Transitions.startTransition:
![](https://file.jishuzhan.net/article/1795108592412528641/9f9ffeb72ab28bb0f3815722e20e2cfd.webp)
这个方法被很多地方调用,但都在WMShell:
![](https://file.jishuzhan.net/article/1795108592412528641/de62bdf999f16cfbac985d89aa948a98.webp)
可以认为这种方式是由WMShell发起了Transition,而我们之前分析的流程是WMCore发起了Transition。并且这里回调IWindowOrganizerController的是startNewTransition,而我们之前分析的流程回调的是startTransition,区别即在于传入的Transition的token是否为null:
![](https://file.jishuzhan.net/article/1795108592412528641/f4d413b46f04dac3408eb87680f5bd10.webp)
而在WindowOrganizerController.startTransition中,判断传入的Transition为null,就说明流程是从WMShell发起的,才会去创建Transition对象:
![](https://file.jishuzhan.net/article/1795108592412528641/40339250a018f555c33a64449e6b1b5f.webp)
看一下这里调用的TransitionController.startCollectOrQueue方法:
![](https://file.jishuzhan.net/article/1795108592412528641/0353ddf20d0bc7b9af4f04991e2f98cb.webp)
我们不讨论排队的情况,并且由于Transition流程是从WMShell发起,所以之前也没有创建过SyncGroup,所以这里是直接调用了TransitionController.moveToCollecting,这个我们之前已经分析过了,重点看下这里的OnStartCollect:
![](https://file.jishuzhan.net/article/1795108592412528641/4bc771e3d47dc97ffc6d2084482c0b86.webp)
它接受一个boolean的参数,用来表示这个Transition的启动是否被推迟了,比较典型的场景是在某个TransitionA过程中灭屏,因为灭屏而新创建的这个TransitionB的启动会被推迟,需要等待TransitionA完成。TransitionA完成的时候TransitionB会被启动,即OnStartCollect的onCollectStarted方法在TransitionA结束的时候才被调用,而一般来说Transition在创建后很快就会被启动,因此这种场景下我们就可以认为TransitionB的启动其实是被推迟了,传参deferred就给一个true值。这个时候会检查TransitionB是否还需要启动,或者是被中止(如果TransitionA完成的时候屏幕已经被唤醒了),具体在RootWindowContainer.applySleepTokens:
![](https://file.jishuzhan.net/article/1795108592412528641/17352e35a4903eda538f62ca405ed61a.webp)
这里只是大概提一嘴,不过多分析。
另外在我们分析的流程中,OnStartCollect的onCollectStarted方法是被立即调用的,即以下内容会立即执行:
![](https://file.jishuzhan.net/article/1795108592412528641/244b19bb8832a97892b70ef37ad2216c.webp)
1)、调用Transition.start,之前分析过不用多说。
2)、调用WindowOrganizerController.applyTransaction,因为Transition是从WMShell发起的,那么WMShell也要引起一些变化才行,不然WMCore这边不知道哪个WindowContainer变化了,哪些WindowContainer要参与动画。要引起变化,靠的就是WindowOrganizerController.applyTransaction,变化的信息则是保存在了WindowContainerTransaction,这方面也不细讲了,之前分析WindowContainerTransaction系列文章的时候有详细分析过。