Android布局优化

Android布局优化

Android的UI渲染机制

以前的彩色电视机,它的标准是每秒50帧画面,看上去非常的流畅。其实人眼感觉到的流畅的画面,需要每秒40–60帧画面。在android中,系统通过VSYNC信号触发对UI的渲染/重绘,UI重绘的时间是16ms,即1000ms/60帧。画面的卡顿就是丢帧,逻辑阻塞造成重绘未完成。

在Android开发者选项当中,选择GPU呈现模式分析,并选中在屏幕上显示为条线状,如下图所示:
Android布局优化_第1张图片
每一条包含三个部分,最底部的蓝色是测量绘制的Display List的时间,上面红色代表OpenGL渲染Display List所需要的时间,在上面黄色CPU等待GPU的时间。最后的那条绿色横线是系统VSYNC时间16ms,尽量所有的条形试图都控制在这条绿色横线之下。

避免OverDraw

过度绘制浪费很多的CPU/GPU资源,Android系统开发者选项中调试GPU过度绘制,并选中显示过度绘制区域(PS:只有android4.2及以上的版本才具备此功能)

Android布局优化_第2张图片

  1. 颜色标识: 从好到差:蓝-绿-淡红-红

    1. 蓝色1x过度绘制
    2. 绿色2x过度绘制
    3. 淡红色3x过度绘制
    4. 红色超过4x过度绘制
  2. 验收标准:

    1. 控制过度绘制为2x
    2. 不允许存在4x过度绘制
    3. 不允许存在面积超过屏幕1/4区域的3x过度绘制(淡红色区域)

避免过度绘制的方法:
1. 在布局层次一样的情况下, 建议使用LinearLayout代替RelativeLayout, 因为LinearLayout性能要稍高一点.
2. 在完成相对较复杂的布局时,建议使用RelativeLayout,RelativeLayout可以简单实现LinearLayout嵌套才能实现的布局.
3. 将可复用的组件抽取出来并通过include标签使用;
4. 使用ViewStub标签来加载一些不常用的布局;
5. 动态地inflation view性能要比SetVisiblity性能要好.当然用VIewStub是最好的选择.
6. 使用merge标签减少布局的嵌套层次
7. 去掉多余的背景颜色
8. 对于有多层背景颜色的Layout来说,留最上面一层的颜色即可,其他底层的颜色都可以去掉
9. 对于使用Selector当背景的Layout(比如ListView的Item,会使用Selector来标记点击,选择等不同的状态),可以将normal状态的color设置为”@android:color/transparent”,来解决对应的问题
10. 内嵌使用包含layout_weight属性的LinearLayout会在绘制时花费昂贵的系统资源,因为每一个子组件都需要被测量两次。在使用ListView与GridView的时候,这个问题显的尤其重要,因为子组件会重复被创建.所以要尽量避免使用Layout_weight
11. 使得Layout宽而浅,而不是窄而深(在Hierarchy Viewer的Tree视图里面体现)

布局优化

布局优化的思想很简单,就是尽量减少布局文件的层级,布局层级少了,自然绘制的时间就短了。
另外的一种方案就是采用用include标签/merge标签和ViewStub。

  • include标签来重用layout代码,可以将一个指定的文件加载到当前的布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:background="@color/all_bg" android:clipChildren="false" tools:context="com.centraltide.tv.suixin.MainActivity">
    <RelativeLayout  android:layout_weight="17" android:layout_width="match_parent" android:layout_height="0dp">
        <include  android:id="@+id/rlTitle" android:layout_width="match_parent" android:layout_height="match_parent" layout="@layout/activity_base_title_layout" />
        <ImageView  android:id="@+id/ivMessage" android:layout_width="wrap_content" android:focusable="true" android:focusableInTouchMode="true" android:layout_centerHorizontal="true" android:layout_height="wrap_content" />
        ...
    </RelativeLayout>
</LinearLayout>

在include标签只支持android:layout_*开头的属性,android:id这是个特例

  • 减少视图层级merge
    merge标签在UI的结构优化中起着非常重要的作用,它可以删减多余的层级,优化UI。merge多用于替换FrameLayout或者当一个布局包含另一个时,merge标签消除视图层次结构中多余的视图组。例如你的主布局文件是垂直布局,引入了一个垂直布局的include,这是如果include布局使用的LinearLayout就没意义了,使用的话反而减慢你的UI表现。这时可以使用merge标签优化。
<merge xmlns:android="http://schemas.android.com/apk/res/android">  

    <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/add"/>  

    <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/delete"/>  

</merge>  

现在,当你添加该布局文件时(使用include标签),系统忽略merge节点并且直接添加两个Button。

  • ViewStub
    ViewStub继承至View,它非常轻量级且宽高都是0,因此它不参与任何的布局和绘制。在实际开发中,很多布局文件正常情况下不会显示,没有必要再整个界面初始化的时候加载进来,使用他并不会影响UI初始化时的性能。各种不常用的布局想进度条、显示错误消息等可以使用ViewStub 标签,以减少内存使用量,加快渲染速度。通过ViewStub就可以做到在使用的时候在加载。
 <ViewStub android:id="@+id/stub_import" android:inflatedId="@+id/panel_import" android:layout="@layout/progress_overlay" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" />

当你想加载布局时,可以使用下面其中一种方法:

((ViewStub)findViewById(R.id.stub_import)).setVisibility(View.VISIBLE);  
// or 
View importPanel = ((ViewStub)findViewById(R.id.stub_import)).inflate();  

当调用inflate()函数的时候,ViewStub被引用的资源替代,并且返回引用的view。 这样程序可以直接得到引用的view而不用再次调用函数findViewById()来查找了。
注:ViewStub目前有个缺陷就是还不支持merge标签。

            今天多一份拼搏、明天多几份欢笑。tks

你可能感兴趣的:(android,UI,优化,布局,布局优化)