从源码角度分析一下三个问题

本文主要研究第三个问题

二、UI是如何绘制的?

前两篇文章主要讲述了Activity的生命周期的调用和setContentView的流程,但是并没有说到是具体怎么进行UI的绘制的,而本章主要说明UI的绘制过程,也是从源码角度讲解:

第一篇文章中提到过一个方法,叫做handleMessage方法,里面有好多Activity的状态,其中有一个状态叫做resume

UI绘制流程详解(3)

而这个方法就是绘制UI的开始,为什么从这个方法开始呢?都知道,onResume这个状态是Activity由不可见变为可见时的过程,所以绘制当然从这个方法开始了,其中有个方法叫做handleResumeActivity,查看它的代码:

UI绘制流程详解(3)

我们发现关键性代码 wm.addView,而参数是decor和l,decor在上片文章中说过,是顶级的View,而l是WindManager的参数,wm是一个抽象类,所以addView的操作是它的实现类调用的,实现类是WindManagerImpl。具体是怎么找的呢?主要是通过a.getWindowManager层层往上找而找到的,这里我就不赘述了。我们查看WindowManagerImpl的addView的方法:

UI绘制流程详解(3)

查看mGlobal的addView的方法:

UI绘制流程详解(3)

第二个红框中,将view,root及wparams存在了相应的list中,view是顶层的View视图;root的类是ViewRootImpl,它的注释是实现了视图和窗口管理器之间的协议;wparams是WindowManager的参数,查看root中的setView代码:

UI绘制流程详解(3)

关键性代码在我看来只有这一句,就是给view设置一个ParentView,而这个view是decor,从上篇文章中可以知道,是顶层视图。那么这句话有什么作用呢,我们接着往下看就知道了。

我们回到ActivityThread的handleResumeAtivity方法中,接着向下找代码:

UI绘制流程详解(3)

这里有一句代码是和layout相关的,而且也是wm进行调的,查看updateViewLayout方法,依然是WindowManagerGlobal方法调用的updataViewLayout方法,查看这个方法

UI绘制流程详解(3)

其中有这么一句代码,给view设置WindowManager的布局参数,从上面我们知道,view的父View是ViewRootImpl,是通过assignParent代码设置,所以这个setLayoutParams就是调用的ViewRootImpl的setLayoutParams,assignParent这个方法的作用到这里就很清楚了。

我们查看ViewRootImpl的setLayoutParams方法代码:

UI绘制流程详解(3)

找到了这句代码,这里我需要说明一下,在代码篇幅比较多的时候怎么才能找到关键的代码呢?无非是两点:(1)找自己熟悉的代码(2)找想要了解的相关的代码,这里我们探究的是layout的相关的东西,所以带有layout的相关的方法就显得比较重要了

requestLayout方法的源代码:

UI绘制流程详解(3)

UI绘制流程详解(3)

在这个方法中没找到关键的代码,还在代码篇幅不多,我们就一个一个去找,在postCallback这个里面,找到了mTraversalRunnable,看看他的源代码:

UI绘制流程详解(3)

只调用了doTraversal这个方法

UI绘制流程详解(3)

进入performTraversals方法中,这个代码的篇幅比较长,但是关键性的代码却很明显,分别找到了performMeasure,performLayout,performDraw,在这三个里又分别调用了measure,layout,draw方法,到这里UI的绘制过程就很清晰了,通过了mearsure,layout,draw过程,我们的UI就展示在了手机上。这篇的代码分析还是比较饶的,所以原代码的阅读是关键,我总结有三点:

(1)找我们认识的方法

(2)找和关键点相关的方法

(3)看源代码的注释

欢迎留言,欢迎纠错,共同进步!

 

相关文章: