震惊!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对象无法生效
相关推荐
alexhilton5 小时前
面向开发者的系统设计:像建筑师一样思考
android·kotlin·android jetpack
CYRUS_STUDIO14 小时前
用 Frida 控制 Android 线程:kill 命令、挂起与恢复全解析
android·linux·逆向
CYRUS_STUDIO14 小时前
Frida 实战:Android JNI 数组 (jobjectArray) 操作全流程解析
android·逆向
用户0917 小时前
Gradle Cache Entries 深度探索
android·java·kotlin
循环不息优化不止17 小时前
安卓 View 绘制机制深度解析
android
叽哥17 小时前
Kotlin学习第 9 课:Kotlin 实战应用:从案例到项目
android·java·kotlin
雨白1 天前
Java 线程通信基础:interrupt、wait 和 notifyAll 详解
android·java
诺诺Okami1 天前
Android Framework-Launcher-UI和组件
android
潘潘潘1 天前
Android线程间通信机制Handler介绍
android
潘潘潘1 天前
Android动态链接库So的加载
android