
在 android 中,若需在布局绘制完成后同步获取两个 view 的真实宽度并用于联合计算(如设置其他控件的 margin),应避免在 `oncreate()` 中直接调用 `getwidth()`,而推荐在 `onstart()` 或更稳妥的 `view.post(runnable)` 中统一读取——后者能确保测量与布局流程彻底结束。
在 Android 视图生命周期中,onCreate() 仅完成布局资源加载和 setContentView() 调用,此时 View 尚未经过测量(measure)、布局(layout)和绘制(draw)三阶段,因此 getWidth() 和 getHeight() 返回值为 0(除非 View 已被强制测量,但不可靠)。你提到已通过 setMargins() 动态修改了 view1 和 view2 的布局参数,这会触发后续的重新测量与布局,但该过程异步发生且不保证在 onCreate() 返回前完成——因此直接读取宽度必然不准。
虽然你观察到两种 post() 写法均“有效”,但存在关键差异:
-
✅ 推荐方式:单次 post() 统一读取
@Override protected void onStart() { super.onStart(); // 更简洁、更可靠:利用 onStart() 时机(绘制已完成) int width1 = view1.getWidth(); int width2 = view2.getWidth(); formula(width1, width2); }根据 Android Activity 生命周期文档,onStart() 被调用时,Activity 已进入前台,其窗口已附加(window attached),所有 View 至少已完成首次完整测量与布局。此时调用 getWidth() 是安全且高效的。
-
⚠️ 可接受但非最优:单个 post() 内读取双 View
view1.post(() -> { int width1 = view1.getWidth(); // 此时 view1 已布局 int width2 = view2.getWidth(); // view2 同样已完成布局(同一轮遍历) formula(width1, width2); });因为 post() 将任务加入主线程消息队列末尾,待当前帧绘制完成后执行,此时整个 View 树已完成 layout 阶段,两个 View 的尺寸均已确定。无需嵌套 post()——view2.post(...) 不仅冗余,还可能因两次调度引入微小延迟或竞态风险(尤其在复杂 UI 下)。
-
❌ 不推荐:分离 post() + 异步读取
view1.post(() -> width1 = view1.getWidth()); view2.post(() -> width2 = view2.getWidth()); // width2 可能先于 width1 赋值!
无法保证执行顺序,formula() 若在外部调用将面临变量未就绪问题;若强行加锁或标志位,反而增加复杂度与出错概率。
? 注意事项:
- 若你的 Activity 启动后立即进入后台(如被电话打断),onStart() 可能被跳过或延迟,此时 post() 更鲁棒。通用最佳实践是:优先尝试 onStart();若逻辑依赖绝对绘制完成(如涉及动画起始、截图、自定义测量适配),则统一使用 view1.post(...)。
- getWidth() 返回的是 px 单位整数,确保 formula() 中的数学运算(如 x + y)符合预期;若需 dp 转换,请使用 TypedValue.applyDimension()。
- 对于 ConstraintLayout,setMargins() 修改后必须调用 setLayoutParams() 触发重布局,你已在 onCreate() 中正确执行,这是前提。
✅ 总结:
使用 onStart() 是最简洁、高效且符合生命周期语义的方案;若需 100% 确保绘制完成(例如兼容某些定制 ROM 或特殊启动场景),则采用 单次 post() 统一读取双 View 尺寸。永远避免嵌套 post() 或分离读取——它们徒增复杂性,无实际收益。









