性能优化3-UI绘制

这几天在闲暇之余,继续研究了性能优化很重要的一个组成部分,UI绘制流程和UI性能优化,这一块还是蛮深的,我简单的跟着源码走了一遍,在此简单记录,以供以后继续深入研究。

  1. 看绘制流程就用Actiivty的setContentView(R.layout.activity_main);入手:

    • 点进Activity.Java类
    public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);//   **①**
        initWindowDecorActionBar();
    }
    • 这里的getWindow()拿到的是Window的实现类PhoneWindow。找到PhoneWindow.Java,在 com.android.internal.policy包下。
    @Override
    public void setContentView(int layoutResID) {
        if (mContentParent == null) {
            installDecor();//**②加载DecorView**
        }
        ……
        mLayoutInflater.inflate(layoutResID, mContentParent);//**⑥最后把我们自己的view放进DecorView中**
    }
    
    private void installDecor() {
        if (mDecor == null) {
            mDecor = generateDecor();//**③生成一个DecorView(继承的FrameLayout)**
            ..............
        if (mContentParent == null) {
            mContentParent = generateLayout(mDecor);//**④根据主题使用不同的布局承载**
        }
    protected ViewGroup generateLayout(DecorView decor) {
        //**⑤省略一堆判断。**
        View in = mLayoutInflater.inflate(layoutResource, null);
        decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
        mContentRoot = (ViewGroup) in;
    }
    • 看下图或许会更清楚。
      Activity加载显示基本流程

    • 类关系图
      类关系图

    • 根据主题使用不同的布局
      根据主题使用不同的布局

    2.继续来看下measure、layout、draw的三个执行流程。这一块是重点也是难点。

    • View.java类
      • measure:测量,测量自己有多大,如果是ViewGroup的话会同时测量里面的子控件的大小
      • layout:摆放里面的子控件bounds(left,top,right,bottom)
      • draw:绘制 (如果直接继承了view一般都会重写onDraw)
    • 这里主要关注一下View.Java源码
      • view的requestLayout()方法开始,递归地不断往上找父容器,最终找到DecorView。ps:DecorView是PhoneWindow的内部类
      • 执行了DecorView的ViewRootImp类的performTranversal()方法 (ViewRootImp类:是PhoneWindow和DecorView的桥梁)
      • performTranversal()方法里面分别调用:
    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
    
    performLayout(lp, desiredWindowWidth, desiredWindowHeight);
    
    performDraw();

    在这里分别调用view的measure,layout,draw方法。

    private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
        try {
            mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
    }

    3.. measure 测试是一个复杂的过程

    • 如何合同的去测量一棵View树 ?如果ViewGroup和View都是直接指定的宽高,那么就不会走测量,测量是因为谷歌设计的自适应尺寸机制(比如Match_parent,Wrap_content) ,造成了宽高不确定,所以就需要进行测量measure过程。measure过程会遍历整颗View树,然后依次测量每一个View的真实的尺寸。(树的遍历–先序遍历)。
    • 这里说一下MeasureSpec,测量规格,int类型32位。然后拿前面两位当做mode,后面30位当做值。

      • mode三种类型:
        • EXACTLY: 精确的。比如给了一个确定的值 100dp
        • AT_MOST: 根据父容器当前的大小,结合你指定的尺寸参考值来考虑你应该是多大尺寸,需要计算(Match_parent,wrap_content就是属于这种)
        • UNSPECIFIED: 最多的意思。根据当前的情况,结合你制定的尺寸参考值来考虑,在不超过父容器给你限定的只存的前提下,来测量你的一个恰好的内容尺寸。
          用的比较少,一般见于ScrollView,ListView(大小不确定,同时大小还是变的。会通过多次测量才能真正决定好宽高。)
      • value:就是宽高的值。
      • 从规格当中获取mode和value:

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
      • 反过来将mode和value合成一个规格呢:

        MeasureSpec.makeMeasureSpec(resultSize, resultMode);
    • 经过大量测量以后,最终确定了自己的宽高,需要调用:

      setMeasuredDimension(w,h)

4.. 这几天一直在研究这一块的东西,时间精力有限,零零散散整理,稍微有些混乱,等有时间再系统的整理一下。这篇文章主要是对于UI绘制流程的理解,关于UI的优化,下次继续整理。

由于技术和文笔有限,很多东西没有说的很透彻,反正你也不能来打我~~

说明一下,文章中的图片是借用的,如果涉嫌侵权,请联系我删除~~~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值