通俗易懂解析Android View绘制流程

173 阅读3分钟

用通俗易懂的方式拆解这篇Android View绘制流程的文章,并补充关键细节:

image.png

一、View的诞生故事(比喻版)
想象你要装修房子:

  1. 开发商交房(Activity创建)时,先安装门窗框架(PhoneWindow和DecorView)

  2. 你设计户型图(setContentView)时:

    • 开发商提供毛坯房(DecorView)
    • 划分出客厅区(标题栏)和装修区(android.R.id.content)
  3. 正式使用前要经过三道工序:

    • 量房阶段(measure):确定每个房间尺寸
    • 摆家具阶段(layout):确定每个家具位置
    • 粉刷阶段(draw):墙面装饰上色

二、核心角色关系

  1. Activity是房东:负责整体事务协调
  2. Window是物业管家:管理房屋结构
  3. View是装修工人:具体执行每个细节
  4. ViewRootImpl是工程监理:协调测量、施工顺序
  5. WMS是城市规划局:最终审批房屋建设

三、绘制流程关键细节

image.png

  1. 首次显示必经之路:
    onResume执行后 → ViewRootImpl开始工作 → measure → layout → draw
    这就是为什么首次onResume时拿不到View尺寸

  2. 测量阶段的秘密会议:

    • 最少测量2次(常规布局)
    • 最多4次(弹窗等特殊布局)
    • 使用MeasureSpec作为"施工图纸",包含尺寸要求和限制模式
  3. 更新UI的三种姿势:

    • invalidate():局部补漆(只重绘)
    • requestLayout():重新量房+摆家具(触发measure+layout)
    • postInvalidate():让工头代叫补漆工(子线程安全重绘)

四、高频面试题精要版

  1. 为什么onResume拿不到宽高?
    就像装修还没开始量房,房东(Activity)当然不知道房间尺寸
  2. 子线程不能更新UI?
    其实在监理(ViewRootImpl)上岗前可以修改,但就像没有安全措施的施工,容易引发事故(线程安全问题)
  3. ViewGroup为何不触发onDraw?
    默认认为它是"透明容器",若要绘制需要:
    ➢ 主动声明setWillNotDraw(false)
    ➢ 添加背景/前景等可视化元素
  4. getWidth和getMeasuredWidth区别?
    前者是实际入住后的房间尺寸,后者是设计图纸上的理论尺寸

五、技术冷知识

  1. 神秘的VSYNC信号:
    像装修队的开工哨声,保证每次绘制都等屏幕刷新信号,避免画面撕裂

  2. DecorView的双层结构:

    • 外层是系统装饰(状态栏/导航栏)
    • 内层是开发者自定义内容
  3. PhoneWindow的独特身份:
    安卓系统中唯一的Window实现类,如同城市中所有建筑必须使用统一建筑标准

理解这些原理后,自定义View就像掌握了装修核心技术,能精准控制每个绘制细节,解决各种UI异常问题。实际开发中遇到布局问题时,可沿着"测量→布局→绘制"的线索逐步排查,如同检查装修工程的每个验收环节。

参考