背景:
在onCreate()中获取view的宽高直接调用getMeasuredWidth/height的话 会因为无法保证是不是已经测量完毕而导致获得的宽高为0,那么如何能确保在onCreate,onStart,omResume方法中获取到宽高呢?如下几种方法:
-
Activity/view的onWindowfocusChanged()方法中获取宽高。
-
view.post(runnable)将runnable投到消息队列的尾部,然后等looper调用此runnable的时候,view已经初始化好了
-
ViewTreeObserver的众多回调中
-
手动调用view.measure方法
那么在第2条中是如何知道view初始化和post的顺序的呢,以及为何即使是在子线程调用view.post也是可以再主线程操作ui的呢?
调用流程:
1. post进来后,先判断view有没有attachedToWindow(attachInfo是否为空),没有就先将过来的Runnable缓存,否则就通过 attachInfo.mhandler将这些runnablepost到主线程对了中等待执行。
2. mAttachInfo是viewRootImpl的成员变量,在构造函数中初始化,并且activity的View树中所有子view的attachInfo都是这个mAttachInfo的引用
3. mAttachInfo.mHandler也是viewRootImpl的成员变量,在声明时就初始化了,所以mHandler绑定的是主线程的handler,所以View.post的操作都会发送到主线程进行执行,因此也就支持ui操作了
4. dispatchAttachedToWindow调用的时机是ViewRootImpl的performTraversals(),该方法会进行对view树measure,layout,draw三大流程的操作
5. 消息机制会在performTraversals这个消息处理完后再处理新来的消息,所以view.post是会在测量后执行。