美文网首页
从View的工作原理介绍Android view的性能优化

从View的工作原理介绍Android view的性能优化

作者: 6e3bd4186e4b | 来源:发表于2017-06-02 16:06 被阅读157次

    在开发过程中,经常会接触到“性能优化”这个问题,比如内存优化、网络优化、视图优化。为了解决优化内存和网络问题,通常的做法都是采用第三方库(比如OkHttp、Glide、Fresco);而关于视图优化,则需要开发者拥有一个好的视图优化的常识。对于我们开发者来说,了解一些View性能优化的常识,增强开发技巧,也是一门必备功课。</br>
      在文章开始前,先提个问题,Android中的xml布局怎么显示到屏幕上的?这个问题涉及很广,从软件到硬件,整个流程我就不花篇幅去讲解,这里有个视频应该能很好的回答这个问题,视频网址:https://www.youtube.com/watch?v=WH9AFhgwmDw
      看完上面的视频之后,我们就一些和开发过程中密切相关的细节做具体分析流程

    第一步 Xml布局文件解析

    xml 布局文件解析流程图

    <b>其中一些优化的标签:<b>

    • ViewStub 标签

        ViewStub就是一个宽高都为0的一个View,它默认是不可见的。只有通过调用 setVisibility() 函数或者 Inflate() 函数才会将其要装载的目标布局给加载出来,从而达到延迟加载的效果。在ViewStub布局可显示之前,系统不会消耗资源去实例化里面的布局,可以节省系统资源消耗。<p>
    • include 标签

        按照官方的意思,include就是为了解决重复定义相同布局的问题。相当于Java代码中将相同的部分抽取出来,然后复用,需要的时候引入它即可,而不必每次都自己写一遍。<p>
    • merge 标签

        merge它可以删减多余的层级,优化UI。例如你的主布局文件是垂直的LinearLayout,这时使用include将目标布局引入进来,新布局也是垂直的LinearLayout,那么这个新的LinearLayout就没有任何意义了。使用的话反而增加计算和绘制时间,这时就可以使用<merge/>标签优化。merge原理就是在解析xml时候,如果是 <merge/> 标签,那么直接将其中的子元素添加到merge 标签parent中,这样就保证了不会引入额外的层级。

    View 绘制流程

    我们都知道,View 的绘制大致分为三个阶段:测量、布局和绘制,这三个阶段各自的作用如下:

    • measure: 计算大小
    • layout:计算位置
    • draw:将视图显示在屏幕上

      大致流程如下:

      View 绘制流程

      如果是一个view树,那么measure、layout、draw都应该是一个递归操作,具体流程如:
    • View树measure流程图

      measure递归操作
    • View树layout流程图

      layout递归操作
    • View树draw流程图

      draw流程图

    View渲染过程

    这里推荐一篇博客http://hukai.me/android-performance-render ,本篇文章就不多讲了。

    常识

    1、减少View层级。这样会加快Inflate解析xml和View的循环遍历过程。

    2、去除不必要的背景。由于在draw的步骤中,会单独绘制背景。因此去除不必要的背景会加快View的绘制。

    3、尽可能少的使用margin、padding。在测量和布局的过程中,对有margin和padding的View会进行单独的处理步骤,这样会花费时间。我们可以在父View中设置margin和padding,从而避免在子View中每个单独设置和配置。

    4、去除不必要的scrollbar。这样能减少draw的流程。

    5、慎用渐变,能减少draw的流程。

    6、View的过渡绘制。

    7、View的频繁重新渲染。

    8、UI线程中进行耗时操作。

    9、冗余资源及错误逻辑导致加载和执行缓慢。简单的说,就是代码写的烂。

    10、频繁触发GC,导致渲染受阻。当系统在短时间内有大量对象销毁,会造成内存抖动,频繁触发GC线程,而GC线程的优先级高于UI线程,因而会造成渲染受阻。

    量化

    上一章节介绍的常识都是一些理论知识,相比之下量化后的数据更有说服力,下面就介绍两个量化的例子:

    1、有背景和没有背景能优化多少?

    没有背景的布局

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >
        <FrameLayout
            android:id="@+id/view_content"
            android:layout_height="match_parent"
            android:layout_width="match_parent"
            >
            <TextView
                android:id="@+id/tv_test"
                android:layout_gravity="center"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="测试hierarchyView"
                />
            </FrameLayout>
    </FrameLayout>
    
    • 没有背景耗时(数据来自Hierarchy View,具体耗时和设备有关):
      • Measure:0.025ms
      • Layout: 0.013ms
      • Draw:0.322ms

    现在给view_content增加一个白色的背景

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >
        <FrameLayout
            android:id="@+id/view_content"
            android:layout_height="match_parent"
            android:layout_width="match_parent"
            android:background = "#ffffff"
            >
            <TextView
                android:id="@+id/tv_test"
                android:layout_gravity="center"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="测试hierarchyView"
                />
            </FrameLayout>
    </FrameLayout>
    
    • 白色背景耗时
      • Measure:0.025ms
      • Layout:0.013ms
      • Draw:2.425ms

    两者对比一下,明显可以看出有背景的耗时多的多,所以在平时开发中一定要慎重使用view background这个属性,它造成的耗时可是个大头。

    2、加一层布局会增加多少耗时?

    先贴上测试代码

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >
        <FrameLayout
            android:id="@+id/view_content"
            android:layout_height="match_parent"
            android:layout_width="match_parent"
            android:background = "#ffffff"
            >
            <TextView
                android:id="@+id/tv_test"
                android:layout_gravity="center"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="测试hierarchyView"
                />
            </FrameLayout>
    </FrameLayout>
    
    • 耗时
      • Measure:0.025ms
      • Layout:0.013ms
      • Draw:2.425ms

    现在把tv_test移到外面来

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >
        <FrameLayout
            android:id="@+id/view_content"
            android:layout_height="match_parent"
            android:layout_width="match_parent"
            android:background = "#ffffff"
            >
        </FrameLayout>
        <TextView
                android:id="@+id/tv_test"
                android:layout_gravity="center"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="测试hierarchyView"
                />
    </FrameLayout>
    
    • 耗时
      • Measure:0.028ms
      • Layout:0.016ms
      • Draw:2.288ms

    两者总耗时比较可以看出扁平化的布局耗时稍微少一点(布局嵌套如果深一点差值会更明显,有兴趣可以试一下),这里也可看出在View的绘制过程中,draw的时间最长。

    工具

    这里介绍常用的两种工具

    结合项目谈优化方案

    目前我们项目Activity数量已经达到252个,也就是说我们的app有252个界面,其中有许多界面都可以做优化,尤其是对一些布局比较复杂,视图比较多的页面可以针对性的做优化,可以从以下几个点进行
    1、检查布局的background属性,看看有没有重叠现象
    2、尽量降低布局嵌套层次
    3、合理使用include、merge、ViewStub等标签
    4、删除冗余的资源

    相关文章

      网友评论

          本文标题:从View的工作原理介绍Android view的性能优化

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