Android 绘制流程

作者: 科技猿人 | 来源:发表于2021-02-03 18:15 被阅读0次

    Read The Fucking Source Code

    引言

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

    源码版本(Android Q — API 29)

    本文涉及应用启动流程

    Android App启动流程

    1. 绘制流程起源概览

    • 大家都知道绘制是从ViewRootImpl进行分发的,由DecorView来进行绘制分发。
    • 那么DecorView是哪儿来的?
    • ViewRootImpl哪儿来的?
    • 应用启动后,在什么时刻进行绘制?
    • 带着这些问题,一起来探索 绘制流程起源

    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 视图模块 全家桶》

    相关文章

      网友评论

        本文标题:Android 绘制流程

        本文链接:https://www.haomeiwen.com/subject/shdmtltx.html