Hacks布局篇-Hack3 使用<merge/>标

作者: diygreen | 来源:发表于2016-05-07 19:44 被阅读323次
    <merge/>

    作者:李旺成

    时间:2016年5月7日


    在这个 Hack 中将详细介绍 <merge /> 标签的使用,以及一些注意事项。

    关于嵌套层级

    Android 开发中关于布局优化有一个很常用的技巧,就是减少布局的嵌套层级。布局的嵌套层级越深,渲染该页面就会越慢,程序的性能也就会越差。

    使用 Hierarchy Viewer 可以比较直观的看到布局的嵌套层级:

    HierarchyViewer使用示例

    常用的减少布局层级的方法是尽量使用 RelativeLayout,往往很多使用 LinearLayout 需要嵌套很多层才能达到的效果,改用 RelativeLayout 可能就不需要嵌套了。

    使用 RelativeLayout 只是一方面,Google 提供了 <merge /> 标签用于减少布局层级来。<merge /> 标签通过删减多余或者额外的层级,从而优化整个 Android 布局的结构。

    注意:如果你打开 HierarchyViewer 却不能查看任何布局,那么可以试试这个 ViewServer

    <merge /> 标签的使用

    <merge/> 多用于替换 FrameLayout 或者当一个布局包含另一个时,<merge/> 标签消除视图层次结构中多余的视图组。例如你的主布局文件是垂直布局,引入了一个垂直布局的 include,这时如果 include 布局使用 LinearLayout 就没意义了,使用的话反而会减慢你的 UI 表现。这时可以使用<merge/> 标签优化。

    替换 FrameLayout

    分别来看一下根标签使用 FrameLayout 与 使用 merge 有什么区别:
    activity_hack3_1.xml :

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout 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:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        tools:context=".Hack3Activity">
        <include
            layout="@layout/header_withmerge"/>
        <include
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom"
            layout="@layout/footer_app_name"/>
    </FrameLayout>
    

    activity_hack3_2.xml :

    <?xml version="1.0" encoding="utf-8"?>
    <merge xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        tools:context=".Hack3Activity">
        <include
            layout="@layout/header_withmerge"/>
        <include
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom"
            android:layout_marginBottom="30dp"
            layout="@layout/footer_app_name"/>
    </merge>
    

    上面两个布局文件差别不大,只是 activity_hack3_2 中使用 merge 替换了 activity_hack3_1 中的 Framelayout,使用 HierarchyViewer 看看这两个布局有什么差别:

    Framelayout做根标签 merge做根标签

    对比上面两张图,发现使用 <merge/> 标签替换 Framelayout 之后可以减少一层。所以,如果用到 Framelayout 作为根布局的地方,大可以直接替换为 merge。

    与 <include /> 配合

    如果要 include 的子布局的根标签是 Framelayout,那么最好替换为 merge,这样可以减少嵌套。

    如果,子布局直接以一个控件为根节点,也就是只有一个控件的情况,这时就没必要再使用 <merge /> 包裹了,如下所示:

    merbe 和 include

    如图所示,这两个 include 的子布局都只有一层,没有其他布局嵌套。

    上图对应的布局代码 activity_hack3.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        ...
        >
        <include
            layout="@layout/header_withmerge"/>
        <include
            layout="@layout/footer_app_name"/>
    </RelativeLayout>
    

    用到的两个子布局:
    header_withmerge.xml

    <?xml version="1.0" encoding="utf-8"?>
    <merge xmlns:android="http://schemas.android.com/apk/res/android">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="40dp"
        android:text="使用了 <merge /> 标签的页眉"
        android:textColor="@android:color/holo_red_light"/>
    </merge>
    

    footer_app_name.xml,前面已经介绍过了,这里就不再赘述。

    作为 ListView Item 的根标签

    这里做个实验,使用根标签为 <merge /> 的布局作为 ListView 的 Item。
    1、创建 Item 布局
    见 item_hack3lv.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <merge xmlns:android="http://schemas.android.com/apk/res/android">
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="使用merge作为ListView Item的根标签"
            android:textColor="@android:color/holo_red_light"/>
    </merge>
    

    不需要多说,就是以 merge 作为根标签。

    2、自定义 Adapter
    这里看看 getView() 方法即可:

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
    //            convertView = mInflater.inflate(R.layout.item_hack3lv, parent, true);
    //            convertView = mInflater.inflate(R.layout.item_hack3lv, parent, false);
            convertView = mInflater.inflate(R.layout.item_hack3lv, null);
        }
        return convertView;
    }
    

    上面的示例代码中,采用了三种方式来 inflate Item 的布局文件。先不要去关注上面的写法是否有误,这里是为了做实验。

    3、为 ListView 设置 Adapter

    mContentLV.setAdapter(new Hack3LVAdapter(this));
    

    看看这三种不同方式所产生的后果:

    inflate(R.layout.item_hack3lv, parent, true) inflate(R.layout.item_hack3lv, parent, false) inflate(R.layout.item_hack3lv, null)

    PS:第二种方式和第三种方式其实是一样的,可以看源码:

    public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
        return inflate(resource, root, root != null);
    }
    
    // 就是调的 public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot)
    

    有兴趣的同学可以去研究下 LayoutInflate,以及 LayoutInflate 的 inflate 方法各个参数的含义和作用,这里就不展开了。

    这里只是的得出一个教训,不要使用 <merge /> 作为 ListView Item 的根节点。

    注意事项

    使用 <merge /> 很简单,但在其使用过程中有些地方需要注意,下面提供一些供参考。

    • <merge /> 只能作为布局的根标签使用
    • 不要使用 <merge /> 作为 ListView Item 的根节点
    • <merge /> 标签不需要设置属性
      写了也不起作用,因为系统会忽略 <merge /> 标签
    • inflate 以 <merge /> 为根标签的布局时要注意
    • 必须指定一个父 ViewGroup
    • 必须设定 attachToRoot 为 true
      也就是说 inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) 方法的二个参数 root 不能为 null,并且第三参数 attachToRoot 必须传 true

    项目地址

    AndroidHacks合集
    布局篇
    个人博客
    示例用到代码见:
    Hack3Activity.java
    Hack3LVAdapter.java
    activity_hack3.xml
    activity_hack3_1.xml
    activity_hack3_2.xml
    item_hack3lv.xml
    header_withmerge.xml

    参考

    Android抽象布局——include、merge 、ViewStub
    Android 性能优化 四 布局优化merge标签的使用

    相关文章

      网友评论

        本文标题:Hacks布局篇-Hack3 使用<merge/>标

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