Android UI绘制

一、Android UI绘制流程及原理

  1. 根据Activity设置布局的方法:setContentView(),来追溯源码中的UI绘制的流程。此方法中执行了window的setContentView()方法, getWindow().setContentView(layoutResID); window类是一个抽象类,是顶级窗口外观和行为策略的抽象基类,PhoneWindow是Window的唯一实现类,Window类的定义如下图。Window的定义

    找到 PhoneWindow 的 setContentView() 方法,如下图:PhoneWindow.setContentView
    图中有两个关键的方法:installDecor();mLayoutInflater.inflate(layoutResID, mContentParent);,installDecor()方法是创建DecorView, 初始化 mContentParent;mLayoutInflater.inflate(layoutResID, mContentParent);方法是将布局 inflate 到已初始化的mContentParent中。

  2. 然后继续进入 installDecor() 方法中查看具体的实现,如下图:PhoneWindow.installDecor
    此方法中有两个关键的方法:generateDecor(-1);generateLayout(mDecor); 。其中 generateDecor(-1); 方法是初始化DecorView的方法,此方法中调用了一个DecorView的构造方法,创建一个DecorView对象。 generateLayout(mDecor); 方法中根据一些配置参数(theme之类的),配置DecorView的布局文件,此时已经给 activity 配置好了主题,并将DecorView中的 id 为 content 的 FrameLayout 返回,赋值给 mContentParent。也就是说:DecorView是PhoneWindow的一个成员变量,是PhoneWindow的顶级View,继承自FrameLayout,是一个ViewGroup,根据主题不同配置不同的布局文件,但DecorView的所有的布局文件中都有个共同的、id为content的FrameLayout;这个FrameLayout就是PhoneWindow的成员变量mContentParent,mContentParent是activity中 setContentView()方法设置的布局的父View,是DecorView中的顶级view。
    流程如下图:View是如何添加到屏幕上

  3. View的绘制流程从 ActivityThread 开始,以下是ActivityThread的定义:ActivityThread的定义
    含义是:这管理应用程序进程中主线程的执行,在活动管理器请求时调度和执行活动,广播以及其他操作。
    ActivityThread就是我们常说的主线程或UI线程,ActivityThread的main方法是整个APP的入口
    ActivityThread中有个handleMessage()方法,处理了Activity的生命周期相关操作,包括activity创建和View绘制相关操作。在API 23中,该方法中有个LAUNCH_ACTIVITY 的case,执行了activity启动的相关操作,但在API 28中谷歌修改了这个实现,没有LAUNCH_ACTIVITY 的case了,与RELAUNCH_ACTIVITY合并处理了。(教程讲的API 23,我用的API 28看的代码)。
    ActivityThread 继承自 ClientTransactionHandler ,此抽象类中封装了handleXXXActivity相关的方法,与Activity生命周期相关。
    回到handleMessage()方法,不管是API 23还是API 28,都有个handleLaunchActivity方法,此方法处理activity的启动,其中有个核心方法performLaunchActivity 处理activity的启动流程;此方法中有个handleResumeActivity 方法处理Activity生命周期的 onResume 方法,我们都知道view的可见是从onResume方法开始的,所以应该是在onResume方法中处理view的绘制;注意到handleResumeActivity 中有个wm.addView(decor,l);根据这个方法一路追溯到最后实际执行的是**WindowManagerGlobal.addView()**方法,此方法中执行了root.setView(view, wparams, panelParentView); 这里将view绘制到parentView上。

  4. 绘制执行的具体方法:
    ViewRootImpl.setView(decorView, layoutParams, parentView) ---->
    ViewRootImpl.requestLayout()---->
    scheduleTraversals()---->
    mChoreographer.postCallback(
    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);(Choreographer编舞者,协调动画输入和绘图的时间)---->
    doTraversal()---->
    performTraversals()
    最后在performTraversals方法中执行绘制的三大步骤:
    测量:ViewRootImpl.performMeasure
    布局:ViewRootImpl.performLayout
    绘制:ViewRootImpl.performDraw

  5. View的绘制流程如下图:View的绘制流程

二、绘制三大流程:测量、布局、绘制

2.1 测量(Measure)

  1. View的测量大小由MeasureSpec决定,MeasureSpec = 模式 + 尺寸,即SpecMode+SpecSize,是一个32位int值,高2位表示模式,低30位表示尺寸。
  2. MeasureSpec有三种,UNSPECIFIED, EXACTLY, AT_MOST
    UNSPECIFIED:父容器不对view做任何限制,系统内部使用;
    EXACTLY:父容器检测出View的大小,View的大小就是SpecSize,即match_parent属性和固定大小(dp);
    AT_MOST:父容器制定一个可用大小,View不能超过这个值,即wrap_content。
  3. View的MeasureSpec由父容器的MeasureSpec和自身LayoutParams决定,具体规则如下图所示:View的MeasureSpec
    最特别的是父容器是AT_MOST(相当于wrap_content),子view是match_parent的情况,此时specSize是parentSize,即子view大小铺满父容器。
  4. 如果view的MeasureSpec的决定因素中有父容器的MeasureSpec,那么顶级view容器DecorView的MeasureSpec的决定规则是什么呢?见下图:DecorView的MeasureSpec
  5. ViewGroup
    measure ---->onMeasure(测量子控件的宽高)---->
    setMeasureDimension---->setMeasureDimensionRaw(保存自己的宽高)
    自定义时,一定要重写onMeasure方法,在onMeasure方法中测量子空间的宽高,再重新确认自己的宽高。
  6. View
    measure ---->onMeasure---->
    setMeasureDimension---->setMeasureDimensionRaw(保存自己的宽高)
    自定义时,一定要重写onMeasure方法,重新确认自己的宽高。

2.2 布局(layout)

  1. ViewGroup
    layout(确定左、上、右、下四个位置) ---->onLayout(进行子View的布局)
    自定义ViewGroup需实现onLayout方法,确定子View的位置。
  2. View
    layout (确定自己的左、上、右、下四个位置)

2.3 绘制(draw)

Android源码中view的绘制有6个步骤,其中关键、必须执行的步骤有四步:ViewGroup的绘制
自定义View:onMeasure()()必须----->onLayout()(不必)----->onDraw()(可选)
自定义ViewGroup:onMeasure()(必须)----->onLayout()(必须)----->onDraw()(可选)
View的绘制是从最底层的DecorView递归往子View绘制

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值