震惊!Android开发竟这样获取View宽高?View.post()原理大揭秘

Android开发竟这样获取View宽高?View.post()原理大揭秘

问题背景

在某些场景下,我们需要在Activity的onCreate方法中获取View的宽高,如果我们直接使用getMeasuredHeight()或是getMeasuredWidth()去获取,得到的值都是0

解决方案

  • 推荐方案:View.post() ✅ 自动处理视图状态,代码简洁
  • ViewTreeObserver
  • 通过MeasureSpec自行测量宽高
  • 使用postDelay()延迟一段时间(不推荐,存在时序风险)
View.post()用法案例
java 复制代码
// 在Activity的onCreate()中
View myView = findViewById(R.id.my_view);
myView.post(new Runnable() {
    @Override
    public void run() {
        int width = myView.getWidth();
        int height = myView.getHeight();
        Log.d("ViewSize", "Width: " + width + ", Height: " + height);
    }
});
View.post()原理要点

核心机制HandlerActionQueue + AttachInfo 双通道保障

  1. ▶️ Attach前:通过HandlerActionQueue缓存任务
  2. ▶️ Attach后:通过主线程Handler立即执行
  3. 🚨 关键限制:必须依附View树才能生效(单独new的View无效)
post方法源码
java 复制代码
 public boolean post(Runnable action) {  
     //1  
     final AttachInfo attachInfo = mAttachInfo;  
     if (attachInfo != null) {  
         return attachInfo.mHandler.post(action);  
     }  
  
     //2
     getRunQueue().post(action);  
     return true;  
  }

主要分为1,2两部分

  1. 如果AttachInfo不为空则调用mHandler.post(action)方法,attachInfo赋值在dispatchAttachedToWindow方法中,该方法会在view执行绘制、测量的时候调用
java 复制代码
void dispatchAttachedToWindow(AttachInfo info, int visibility) {  
    //1、mAttachInfo赋值  
    mAttachInfo = info;  
  
    //2、 执行之前挂起的所有任务,这里的任务是通过 getRunQueue().post(action)挂起的任务, 也就是View.post()方法中当attachInfo为null时执行的那行代码
    if (mRunQueue != null) {  
        mRunQueue.executeActions(info.mHandler);  
        mRunQueue = null;  
    }  
  
    //3、回调View的onAttachedToWindow方法,该方法在onResume之后,View绘制之前执行  
    onAttachedToWindow();   
}  
  1. 如果attachInfo为空也就是当前执行View.post()方法时还没有绘制view,此时会执行getRunQueue().post(action)
java 复制代码
private HandlerActionQueue getRunQueue() {  
   if (mRunQueue == null) {  
        mRunQueue = new HandlerActionQueue();  
    }  
    return mRunQueue;  
}

HandlerActionQueue中主要是将Runnable任务保存到了队列中,等到dispatchAttachedToWindow的时机进行执行。也就是说即使我们调用View.post()方法的时候还没有执行view的绘制流程,View.post()方法也会将我们的Runnable任务挂起,等待合适的时机执行

总结

要点 说明
最佳实践 优先使用View.post()获取视图尺寸
执行时机 保证在measure/layout之后,首帧绘制前执行
线程安全 自动切换到主线程执行
注意事项 View必须已附加到Window,单独创建的View对象无法生效
相关推荐
_李小白2 小时前
【Android FrameWork】第二十六天:BroadcastReceiver
android
@#---3 小时前
如何准确判断json文件并且拿到我想要的信息
android·python·json
程序员陆业聪5 小时前
Android插件化原理与方案详解
android
惟恋惜7 小时前
Jetpack Compose 界面元素状态(UI Element State)详解
android·ui·android jetpack
_李小白7 小时前
【Android FrameWork】延伸阅读:IGraphicBufferProducer驱动UI绘制过程
android·ui
_李小白9 小时前
【Android FrameWork】第二十八天:Activity 的 UI 绘制全过程
android·ui
_李小白9 小时前
【Android FrameWork】第三十天:Surface创建流程解析
android
元亓亓亓9 小时前
考研408--操作系统--day8--操作系统--虚拟内存&请求分页&页面置换/分配
android·java·开发语言·虚拟内存
有位神秘人10 小时前
Android的Compose系列之文本TextView
android
Engineer-Jsp10 小时前
Flutter 开发 Android 原生开发神器 flutter_api_stub
android·flutter