【Android】View#post执行时机浅谈
一,概述
view.post传入一个Runnable,一般在view即将显示时,会调用Runnable,本文结合源码浅谈下post时机。
二,源码
1,每个View被添加到window时,都会保存一个AttachInfo,这个AttachInfo在View#dispatchWindowAttach时赋值,一个Window对应一个ViewRootImpl,在ViewRootImpl的构造方法中,创建了一个实例,如下
AttachInfo保存了WindowSession、IWindow.Stub、Display等信息,如下
AttachInfo确认了一个View所在Surface的物理参数集合,同WMS通信的Binder等信息。
那么何时AttachInfo被赋值给子View?
答案是View#dispatchAttachedToWindow回调
此回调在ViewRootImpl#performTraversals中被执行,从host,即顶层View(setView赋值给ViewRootImpl)下方到View树。且执行时机早于performLayout流程。
而众所周知,Developer一般在LifeCycler#Resume中,performTraversals未开始,因此,通过post方式就能在attach时,执行指定逻辑,笔者进一步跟进当mAttachInfo未附加时的情况,即2
2,通过RunQueue添加此次action,
这是一个HandlerActionQueue,本质就是一个数组构成的Queue,用来存储Runnable
那么这个队列和mAttachInfo#handler什么关系?
在ViewRootImpl#performTraversals中,当dispatchAttachedToWindow后,便会拿到这个Queue,执行executeActions方法,传入的mAttacher#mHandler对象,
很简单,只是简单将RunQueue的Runnable再次存放进Handler对应的MessageQueue中,
而此次是在ViewRootImpl#performTraversals添加到MessageQueue,意味着必须等待View树三大流程(layout、measure、draw)执行完毕后,才会执行到传入的Runnable。
以上分析完毕,直接说结论
三,结论
View#post的Runnable,最早在ViewRootImpl#performTraversals执行完毕后,从MessageQueue顺序执行