android每日面试题3之如何获取view的宽高?

这两天右眼跳,不知道要发生什么事情。白天没有看知识,看到一个这样的问题,如何获取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的时候就是获取宽高的时候。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值