直播平台搭建探索App性能优化之布局优化

一、页面布局对App性能的影响和原因
布局性能主要影响 :App的页面显示速度。
布局影响性能的实质:页面的测量 & 绘制时间,一个页面通过递归完成测量 & 绘制过程。
二、优化思路
合理的布局性能、布局层级、布局复用性 和 按需加载(测量&绘制时间)。
在布局优化中,Android的官方提到了这三种标签、、,下面也是简单说一下它们的优势,以及怎么使用。
三、具体方案
(一) 提高布局的复用性
1、作用:提取布局间的公共部分,通过提高布局的复用性从而减少测量 & 绘制时间。
2、使用:

<include layout="@layout/titlebar"/>

<TextView 
   android:layout_width=”match_parent”
   android:layout_height="wrap_content"
   android:text="@string/Hello World"
   android:padding="10dp" />
3、特别注意: (1)include标签可以使用单独的layout属性,这个也是必须使用的。 (2)include标签若指定了id属性,而layout也定义了id,则layout的id会被覆盖。

(二) 减少视图层级
1、作用:减少布局层级,配合include标签使用,可优化加载布局文件时的资源消耗。
2、使用:
merge标签在UI的结构优化中起着非常重要的作用,它可以删减多余的层级,优化UI。merge多用于替换FrameLayout或者当一个布局包含另一个时,merge标签消除视图层次结构中多余的视图组。
例如:你的主布局文件是相对布局,引入了一个相对布局的include,这时include布局使用的RelativeLayout就没意义了,反而减慢UI渲染。这时可以使用merge标签优化。

//布局A:layout_a.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dp_10"/>
    <TextView
        android:id="@+id/textview"
        android:layout_width="match_parent"
        android:layout_heig

ht="@dimen/dp_10"/>

//布局B:layout_b.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <Button
        android:id="@+id/Button"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginBottom="@dimen/dp_10" />
        
    <include layout="@layout/layout_a.xml" />
</RelativeLayout>

复制代码在上述例子,在布局B中通过标签引用布局A,

此时B布局层级为 =  RelativeLayout ->> Button
                                   —>> RelativeLayout 
                                            ->> Button
                                            ->> TextView

复制代码现在使用merge优化,将被引用布局A根标签的RelativeLayout改为merge。那么在引用布局A时,布局A中的merge标签内容根节点RelativeLayout会被去掉,在include标签里存放的是布局A中的merge标签为根节点的子节点即include里存放的是:ButttonTextView

 此时B布局层级为 =  RelativeLayout ->> Button 
                                 ->> Button
                                 ->> TextView

复制代码即已去掉之前无意义且多余的,

//布局A:layout_a.xml
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dp_10"/>
    <TextView
        android:id="@+id/textview"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dp_10"/>
</merge>

(三) 按需加载
1、作用:按需加载 外部引入的布局,注:属轻量级View、不占用显示 & 位置。
标签最大的优点是当你需要时才会加载,使用它并不会影响UI初始化时的性能。各种不常用的布局想进度条、显示错误消息等可以使用标签,以减少内存使用量,加快渲染速度。是一个不可见的,大小为0的View。

2、使用:

    // 步骤1、先设置好预显示的布局
    // 步骤2、在其他布局通过<ViewStub>标签引入外部布局(类似<include>)
                注:此时该布局还未被加载显示。
    // 步骤3、只有当ViewStub被设置为可见ViewStub.setVisibility(View.VISIBLE)或者
                调用ViewStub.inflate()时,ViewStub所指向的布局文件才会被inflate、
                    实例化,最终 显示<ViewStub>指向的布局。

   /** 
     * 实例说明:在布局A中引入布局B,只有在特定时刻C中才显示
     */  
     // 步骤1:先设置好预显示的布局B = layout_b.xml
     <?xml version="1.0" encoding="utf-8"?>
     <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
        <Button
            android:id="@+id/button"
            android:layout_width="match_parent"
            android:layout_height="@dimen/dp_10"/>
        <TextView
            android:id="@+id/textview"
            android:layout_width="match_parent"
            android:layout_height="@dimen/dp_10"/>
    </RelativeLayout>

    // 步骤2:在布局A通过<ViewStub>标签引入布局B(类似<include>);注:此时该布局还未被加载显示
    // 布局A:layout_a.xml
    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
        <Button
            android:id="@+id/Button"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginBottom="@dimen/dp_10" />
        <ViewStub
            android:id="@+id/Blayout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout="@layout/layout_b" />
    </RelativeLayout>

    // 步骤3:
    只有当ViewStub被设置为可见 / 调用了ViewStub.inflate()时,ViewStub所指向的布局文件
        才会被inflate 、实例化,最终 显示<ViewStub>指向的布局
    ViewStub stub = (ViewStub) findViewById(R.id.Blayout);   
    stub.setVisibility(View.VISIBLE);
    //or
    stub.inflate();

3、特别注意:
(1) ViewStub中的layout布局不能使用merge标签,否则会报错。
(2)ViewStub的inflate只能执行一次,显示了之后,就不能再使用ViewStub控制它了。
(3)与View.setVisible(View.Gone)的区别:

共同点:初始时不会显示

不同点:ViewStub标签只会在显示时,才会渲染整个布局。View.GONE在初始化布局树的时候就已经添加在布局树上了。相比之下ViewStub标签节省布局文件的解析时间和内存的占用,从而具有更高的效率。

(四) 选择耗费性能较少的布局
1、性能耗费低的布局 = 功能简单 = LinearLayout、FrameLayout
2、性能耗费高的布局 = 功能复杂 = RelativeLayout,即布局过程需消耗更多性能(CPU资源 & 时间)
3、嵌套多个布局所耗费的性能 > 单个布局本身耗费的性能,即完成需求时:宁选择单个耗费性能高的布局,也不采用嵌套多个耗费性能低的布局。
4、通过合理选择布局类型,从而减少嵌套。即:完成复杂的UI效果时,尽可能选择1个功能复杂的布局(如RelativeLayout)完成,而不要选择多个功能简单的布局(如LinerLayout)通过嵌套完成。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章