Android 布局优化

01.常见布局优化方法

  • 布局优化的核心就是尽量减少布局文件的层级,常见的方式有:
    • 多嵌套情况下可使用RelativeLayout减少嵌套。
    • 布局层级相同的情况下使用LinearLayout,它比RelativeLayout更高效。
    • 使用标签重用布局、标签减少层级、标签懒加载。
    • 当有多个组件有相似的属性时,可以使用styles,复用样式定义;
    • 通过定义drawable来替代图片资源的使用,降低内存消耗;

02.使用include标签

  • 如下所示

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white">

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

    <org.yczbj.ycrefreshviewlib.YCRefreshView
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_progress="@layout/view_custom_loading_data"
    app:layout_empty="@layout/view_custom_empty_data" />


    </LinearLayout>
  • 注意问题

    • 标签可以使用单独的layout属性,这个也是必须使用的。
    • 可以使用其他属性。标签若指定了ID属性,而你的layout也定义了ID,则你的layout的ID会被覆盖。
    • 在include标签中所有的android:layout_都是有效的,前提是必须要写layout_width和layout_height两个属性。
    • 标签是作为标签的一种辅助扩展来使用的,它的主要作用是为了防止在引用布局文件时引用文件时产生多余的布局嵌套。布局嵌套越多,解析起来就越耗时,性能就越差。因此编写布局文件时应该让嵌套的层数越少越好。
    • 举例:比如在LinearLayout里边使用一个布局。里边又有一个LinearLayout,那么其实就存在了多余的布局嵌套,使用merge可以解决这个问题。

03.ViewStub深度解析

  • 这个标签最大的优点是当你需要时才会加载,使用他并不会影响UI初始化时的性能。

    • 各种不常用的布局想进度条、显示错误消息等可以使用这个标签,以减少内存使用量,加快渲染速度。
    1
    2
    3
    4
    5
    6
    7
    <ViewStub  
    android:id="@+id/view_error"
    android:inflatedId="@+id/panel_import"
    android:layout="@layout/progress_overlay"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom" />
  • 当你想加载布局时,可以使用下面其中一种方法:

    1
    2
    3
    ((ViewStub) findViewById(R.id.stub_import)).setVisibility(View.VISIBLE);  
    // or
    View importPanel = ((ViewStub) findViewById(R.id.stub_import)).inflate();
  • ViewStub有大小吗,会不会绘制,如何做到的?

    • ViewStub也是View的一种,但是没有大小,没有绘制功能,也不参与布局,资源消耗非常低,可以认为完全不影响性能。
    • ViewStub所加载的布局是不可以使用标签的,因此这有可能导致加载出来出来的布局存在着多余的嵌套结构。

04.视图层级<merge/>

  • 这个标签在UI的结构优化中起着非常重要的作用,它可以删减多余的层级,优化UI。

    • <merge/>多用于替换FrameLayout或者当一个布局包含另一个时,标签消除视图层次结构中多余的视图组。例如你的主布局文件是垂直布局,引入了一个垂直布局的include,这是如果include布局使用的LinearLayout就没意义了,使用的话反而减慢你的UI表现。这时可以使用标签优化。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <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>
  • 注意:当你添加该布局文件时(使用标签),系统忽略节点并且直接添加两个Button。

  • 但是就有一点不好,无法预览布局效果!

05.其他一些小建议

  • 减少太多重叠的背景(overdraw)
    • 这个问题其实最容易解决,建议就是检查你在布局和代码中设置的背景,有些背景是隐藏在底下的,它永远不可能显示出来,这种没必要的背景一定要移除,因为它很可能会严重影响到app的性能。如果采用的是selector的背景,将normal状态的color设置为”@android:color/transparent”,也同样可以解决问题。
  • 避免复杂的Layout层级
    • 这里的建议比较多一些,首先推荐使用Android提供的布局工具Hierarchy Viewer来检查和优化布局。第一个建议是:如果嵌套的线性布局加深了布局层次,可以使用相对布局来取代。第二个建议是:用标签来合并布局。第三个建议是:用标签来重用布局,抽取通用的布局可以让布局的逻辑更清晰明了。记住,这些建议的最终目的都是使得你的Layout在Hierarchy Viewer里变得宽而浅,而不是窄而深。
    • 总结:可以考虑多使用merge和include,ViewStub。尽量使布局浅平,根布局尽量少使用RelactivityLayout,因为RelactivityLayout每次需要测量2次。