震惊!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对象无法生效
相关推荐
Cao_Shixin攻城狮2 小时前
Flutter运行Android项目时显示java版本不兼容(Unsupported class file major version 65)的处理
android·java·flutter
呼啦啦呼啦啦啦啦啦啦5 小时前
利用pdfjs实现的pdf预览简单demo(包含翻页功能)
android·javascript·pdf
idjl7 小时前
Mysql测试题
android·adb
游戏开发爱好者89 小时前
iOS App 电池消耗管理与优化 提升用户体验的完整指南
android·ios·小程序·https·uni-app·iphone·webview
人生游戏牛马NPC1号10 小时前
学习 Flutter (四):玩安卓项目实战 - 中
android·学习·flutter
星辰也为你祝福h11 小时前
Android原生Dialog
android
梁同学与Android12 小时前
Android ---【CPU优化】需要优化的原因及优化的地方
android
Misha韩13 小时前
React Native 基础tabBar和自定义tabBar - bottom-tabs
android·react native
iHero13 小时前
【Nextcloud】在 Ubuntu 22.04.3 LTS 上的 Nextcloud Hub 10 (31.0.2) 后台任务cron 的优化
android·linux·ubuntu·nextcloud
yuanlaile17 小时前
Flutter Android打包学习指南
android·flutter·flutter打包·flutter android