1. view.post(Runnable)
public boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
//dispatchAttachedToWindow里赋值mAttachInfo,将view添加到window中
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}
// Postpone the runnable until we know on which thread it needs to run.
// Assume that the runnable will be successfully placed after attach.
getRunQueue().post(action);
return true;
}
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
mAttachInfo = info;
//注意此处,view attach到Window后,会执行缓存的Runnable
if (mRunQueue != null) {
mRunQueue.executeActions(info.mHandler);
mRunQueue = null;
}
}
2.当mAttachInfo为null时,会将Runnable进行缓存 getRunQueue()
public class HandlerActionQueue {
// HandlerAction封装Runnable和delayTime
private HandlerAction[] mActions;
private int mCount;
public void post(Runnable action) {
postDelayed(action, 0);
}
public void postDelayed(Runnable action, long delayMillis) {
final HandlerAction handlerAction = new HandlerAction(action, delayMillis);
synchronized (this) {
if (mActions == null) {
// 此处大小为4,支持增长的的数组
mActions = new HandlerAction[4];
}
mActions = GrowingArrayUtils.append(mActions, mCount, handlerAction);
mCount++;
}
}
//缓存的Runnable的执行
public void executeActions(Handler handler) {
synchronized (this) {
final HandlerAction[] actions = mActions;
for (int i = 0, count = mCount; i < count; i++) {
final HandlerAction handlerAction = actions[i];
handler.postDelayed(handlerAction.action, handlerAction.delay);
}
mActions = null;
mCount = 0;
}
}
}
3.dispatchAttachedToWindow(AttachInfo)掉用
public final class ViewRootImpl implements ViewParent,
View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {
final ViewRootHandler mHandler = new ViewRootHandler();
public ViewRootImpl(Context context, Display display) {
mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,context);
}
private void performTraversals() {
//host即为ViewRootImpl中的setView中的view
host.dispatchAttachedToWindow(mAttachInfo, 0);
}
}
4.都在performTraversals中怎么能保证一定是在View的绘制流程完成之后才去执行dispatchAttachedToWindow?
View的绘制操作其实也是一个Runnable对象,所以必须会执行完绘制这个Runnable后才会执行dispatchAttachedToWindow中添加的Runnable(因为dispatchAttachedToWindow是在绘制这个Runnable中执行的)
dispatchAttachedToWindow方法中会执行public void executeActions(Handler handler) {
//此处将缓存的Runnable的重新通过handler发送到MessageQueue中
}
5.获取View 宽高的方式
- onWindowFocusChanged方法
Activity的窗口得到焦点时,View已经初始化完成,此时获取到的View的宽高是准确的 - View.post()来实现
通过post可以将一个Runnable放置到消息队列中,等到Looper调用此Runnable时,View已经初始化完成。 - ViewTreeObserver的OnGlobalLayoutListener回调
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_get_height);
textView = findViewById(R.id.tv);
final ViewTreeObserver viewTreeObserver = textView.getViewTreeObserver();
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
viewTreeObserver.removeOnGlobalLayoutListener(this);
Log.d("tv_width", "" + textView.getWidth());
Log.d("tv_height", "" + textView.getHeight());
}
});
}