这两天右眼跳,不知道要发生什么事情。白天没有看知识,看到一个这样的问题,如何获取view的宽高。之前遇到过这个问题,百度了一下就解决了。刚刚查文章才知道一点为什么才能获取到view的宽高。
记得之前要获取view的宽高,在onCreate中获取布局中TextView中宽高发现是获取不到的。都是为0,最后通过view.post方法获取到view的宽高的。
textview.getwidth()
textview.getheight()
传进来一个线程对象,给attachinfo赋值,然后下面有个队列执行这个传过来的线程。看一看 getRunQuenu.post执行了啥。
最后还是只执行了postDelayed方法包装成了一个HandlerAction方法。我们看看哪里用到了这个action数组。
这里通过handler执行了这个线程。
发现在View执行dispatchAttachedToWindow方法时,才开始处理我们的Runable对象。handler是哪里来的呢,发送的是那个线程里面呢?第一行发现这个handler是在attchinfo里面赋值过来的。哪里调用的dispathattchtowindow方法呢,然后就能找到handler赋值的地方。
当我在View内部搜索何时调用dispatchAttachedToWindow时,并没有找到。但是View的绘制、测量、布局,都由有父布局开始,所以我们在父布局的中查找调用的地方。
发现都是他的子view调用的这个方法。查资料发现DecorView的dispatchAttachedToWindow()。View的测量、布局、绘制都是从DecorView开始,都是在ViewRootImpl内的performTraversals()内调用,所以我们接下来看一下performTraversals()核心代码。它的作用就是遍历整个View树,并且按照要求进行measure,layout和draw流程。
private void performTraversals() {
// cache mView since it is used so much below...
final View host = mView;
//判断第一次
if (mFirst) {
.....
host.dispatchAttachedToWindow(mAttachInfo, 0);
mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
dispatchApplyInsets(host);
//Log.i(mTag, "Screen on initialized: " + attachInfo.mKeepScreenOn);
.....
}
mFirst=false
...
// Execute enqueued actions on every traversal in case a detached view enqueued an action
getRunQueue().executeActions(mAttachInfo.mHandler);
...
performMeasure();
...
performLayout();
...
performDraw();
...
发现这个里面有mAttachInfo这个对象。
...
final View.AttachInfo mAttachInfo;
...
// mAttachInfo 这里被赋值了,发现了 mHandler。
mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,
context);
// mHandler初始化。
final ViewRootHandler mHandler = new ViewRootHandler();
/*
通过这句代码我们就可以知道。这里 new 的时候是无参构造函数,那默认绑定的就是当前线程的 Looper,而这句 new 代码是在主线程中执行的,所以这个 Handler 绑定的也就是主线程的 Looper
*/
再结合:getRunQueue().executeActions(mAttachInfo.mHandler);
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;
}
}
所以他是发送到主线程中,然后就可以更新UI了。
然后performtraversal()这个方法是什么时候执行的呢??
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
//performTraversals() 在这里被执行
performTraversals();
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}
mTraversalScheduled这个参数在哪赋值才会执行到里面。下面这个方法。
scheduleTraversals
当执行到view的post方法的时候dispathtowindow方法,而走这个方法之前会走performtraverlsra方法也就是测量,布局,绘制。这个方法执行需要看view的绘制流程走到requestlayout方法会调用到。 也就是哪个队列执行handleraction的时候就是获取宽高的时候。