Android 视图模块

Android 绘制流程

2021-02-03  本文已影响0人  科技猿人

Read The Fucking Source Code

引言

Android的绘制流程是什么?
onMeasure,onLayout,onDraw???这已经是绘制分发流程了。
现在一起探索 绘制流程起源

源码版本(Android Q — API 29)

本文涉及应用启动流程

Android App启动流程

1. 绘制流程起源概览

2. 绘制流程起源刨析

2.1 创建PhoneWindow

2.2 创建DecorView

2.3 WindowManager添加DecorView

2.4 创建ViewRootImpl

2.5 添加视图到WMS

2.6 Vsync时钟触发绘制流程

3. Android绘制流程起源汇总

4. 问题思考

ViewRootImpl和DecorView的到底是怎样的关系?

  • Android中Window是View的载体,每个Window下都挂着一棵View树,每个Window的最顶层View是DecorView。
  • ViewParent指明了父View要实现的职责,ViewGroup就实现了这个接口,ViewGroup是包裹View的对象。
  • ViewRootImpl实现了ViewParent,接管了DecorView的ViewParent职责,关于View的对外工作(比如刷新时钟/input输入)都需要ViewRootImpl来处理。
  • ViewRootImpl可以理解为View的外交大臣。因为ViewRootImpl并不是一个真正的View,它只是接管了DecorView的ViewParent职责,把ViewRootImpl说成是DecorView的父亲并不准确。应该是DecorView的干爹(果然还是干爹香啊)。

View的绘制流程主要是指measure、layout、draw。简述一下各自职责。

  • measure确定View的测量宽/高
  • layout确定View的最终宽/高和四个顶点的位置
  • draw则将View绘制到屏幕上

首次 View 的绘制流程是在什么时候触发的?

  • ActivityThread.handleResumeActivity 里触发的。
  • 最终通过 WindowManagerImpl.addView -> WindowManagerGlobal.addView -> ViewRootImpl.setView -> ViewRootImpl.requestLayout 就触发了第一次 View 的绘制。

DecorView 的布局是什么样的?

  • 对于 Activity 的层级,Activity -> PhoneWindow -> DecorView -> [title_bar, content],其中 DecorView里包括了 title_bar 和 content 两个 View,不过这个是默认的布局,实际上根据不同的主题样式,DecorView 对应有不同的布局。
  • DecorView默认布局是:R.layout.screen_simple 。那DecorView的布局是根据什么来设置的?theme…

Activity、PhoneWindow、DecorView、ViewRootImpl 的关系?
PhoneWindow 其实是 Window 的唯一子类,是 Activity 和 View 交互系统的中间层,而 DecorView 是整个 View 层级的最顶层,ViewRootImpl 是 DecorView 的 parent,但是他并不是一个真正的 View,只是继承了 ViewParent 接口,用来掌管 View 的各种事件,包括 requestLayout、invalidate、dispatchInputEvent 等等。

为什么在 Activity 的生命周期里无法获得测量宽高?有什么方法可以解决这个问题吗?

  • 因为 View 的测量过程和 Activity 的生命周期没有任何关系。因为它在生命周期结束之后才开始。
  • 解决方案 1:View还没开始分发测量绘制时,就会创建一个长度为4的HandlerAction(包含Runnable)数组。ViewRootImpl在调用AttchInfo对象的dispatchAttachedToWindow()方法时,将HandlerActionQueue中的缓存Runnable取出加入到ViewRootImpl的Handler中,因为绘制刷新的事件使用了Handler的同步屏障(也就是高优先级的消息),所以只能等待测量绘制结束后,才会去处理之前添加的缓存Runnable,所以在Runnable的处理中,再去拿测量宽高就是正常的。
  • 方案 2:通过设置ViewTreeObserver的OnDrawListener来进行获取(举例:mRootView.getViewTreeObserver().addOnDrawListener(省略))。因为ViewRootImpl在performMeasure、performLayout等方法后会调用mAttchInfo.mTreeObserver.dispatchOnPreDraw方法。所以可以监控。

小编的扩展链接

《Android 视图模块 全家桶》

上一篇下一篇

猜你喜欢

热点阅读