回答:不确定。?首次 onResume 无效,二次 onResume 就有效了。
回顾「Android 基础技术——addView 流程」,首次 onResume 后?window&DectorView绑定,?都还没刷新,更别谈度量,谈何宽高
1)如果在 onResume?生命周期里?用 Handler.post?来?View.getWidth?呢??
不可以
onMeasure() 、onlayout()?也是一个 MSG,post 的时候,ui?刷新需要时间,首次 onResume 的时候都还没有刷新,所以拿不到
ViewRootImpl.scheduleTraversals?会创建消息屏障
添加消息屏障-〉执行Ui?刷新-〉消除消息屏障
消息屏障的作用:保障?ui?刷新?保障16.7ms?刷新一次
2)如果在onResume?生命周期里?用Handler.postDelay?1S?来?View.getWidth?呢??
可以
因为 Ui?刷新已经完成
3)如果用View.post
可以?
对于View.post?调用的时候
如果View已经attach到window,直接调用UI线程的Handler发送runnable。
如果View还未attach到window,将 runnable 放入?ViewRootImpl的RunQueue?中,而不是通过MessageQueue。
RunQueue的作用类似于MessageQueue,只不过这里面的所有runnable最后的执行时机,是在下一个 performTraversals 到来的时候,也就是view完成layout之后,这个时候能第一时间获取宽高,MessageQueue里的消息处理的则是下一次loop到来的时候。
换句话,View.post 的时候是一定能获取到宽高,但是 handler.post 可能还获取不到宽高。view.post 执行时候,view 层次结构已经 measure、layout 并且至少绘制完成了一次了。
1)Activity/View#onWindowFocusChanged
onWindowFocusChanged的含义:View 已经初始化完毕了,宽/高已经准备好了,这个时候获取宽/高是没有问题的。当 Activity 的当前Window获得或失去焦点时会回调此方法,也就是说当Activity暂停执行和继续执行都会回调此方法,即这个方法会被频繁调用。我们一般在第一次获取焦点时获取宽高。
2)view.post(runnable)
利用?Handler?通信机制,通过post将添加一个?Runnable到message?queue的队尾,当View初始化完成之后,Looper会调用此runnable,然后通知UI线程。
3)ViewTreeObserver
当View树状态发生改变,或者View树内部的view的可见性发生改变时,onGlobalLayout会被回调,所以这也是获取宽高的一个很好的时机。伴随着View树的状态的改变,onGlobalLayout会被调用多次,因此可在第一次调用完后,移除监听事件。
4)View#addOnLayoutChangeListener
监听?View的onLayout()的绘制过程,一旦宽/高发生变化就会回调onLayoutChange方法。因此可在第一次调用完后,移除监听事件。