美文网首页android系统控件Android技术知识Android知识
这种情况,可能需要使用merge标签

这种情况,可能需要使用merge标签

作者: b496178cdc84 | 来源:发表于2017-04-12 22:04 被阅读1470次

最近做项目优化,有一些小新得体会和大家分享,本文偏向那些不经常使用或者对merge不太熟悉的开发者,如果你经常使用,或者已经十分的了解merge,那就可以离开了,因为看这个也许是在浪费时间,不过如果你也想复习一下,那不妨来看一看顺便帮我指出错误。
本文纯属个人观点,如果有错误,你来打我啊。
OK,不多废话简单的回忆一下View的绘制过程。

Activity对象创建完毕后,会创建decorview对象,并将decorview对象放到window中。然后会将decorview 和 viewrootimpl关联起来, 整个绘制流程就从
viewrootimpl的preformal... 方法开始。

从最顶级的decorview到我们自己创建的contentview再到我们contentview中的view或者自定义view,这些View 无一例外的要经过一下过程

<b>onMeasure</b>
<b>onLayout</b>
<b>onDraw</b>
<b>以上几个方法,在我之前的文章里面有分析,如果很陌生,可以看一下,入个门。</b>

也就是说,每个View都会经历这三个步骤,如果这个View有子View的话,在onMeasure onlayout ondraw 这三个方法处理的方式 基本都是相同的,先是遍历子View树,然后测量、layout、draw。每一步测量都是耗时的,view树越深,耗时越多,所以,在我们在书写xml布局的时候,尽量要减少多余层级的嵌套。这时候,merge标签就很有用了。

我们先看一个简单的例子,因为可能很多人也都有写过。<b>自定义组合View</b>

public class MyView extends RelativeLayout {
    public MyView(Context context) {
        this(context, null);
    }

    public MyView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initViews();
    }

    private void initViews() {
        LayoutInflater.from(getContext()).inflate(R.layout.view_myview, this);
    }
}

然后布局文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <TextView
        android:id="@+id/first"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:text="我爱稀土掘金"/>


    <TextView
        android:layout_below="@+id/first"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="我爱稀土掘金"/>

</RelativeLayout>

运行结果

Paste_Image.png

也是so easy

OK,你可能会问了,这有什么东西吗?
我们来看一下View的层级

Paste_Image.png

没错,多了一层,也就是MyView明明可以很好的承载两个TextView,为什么还要多一个ViewGroup承载呢?我们作为一名开发者,不能容忍任何性能的消耗,所以这种情况,我们可能需要使用merge标签

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">

<TextView
    android:id="@+id/first"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginLeft="10dp"
    android:text="我爱稀土掘金"/>


<TextView
    android:layout_below="@+id/first"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="我爱稀土掘金"/>

</merge>

OK在运行一下

Paste_Image.png Paste_Image.png

成功消去那一层,胜利了。
那是不是什么情况都可以这么搞呢?其实肯定不是的,比如说

public class MyView extends LinearLayout {
    public MyView(Context context) {
        this(context, null);
    }

    public MyView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initViews();
    }

    private void initViews() {
        LayoutInflater.from(getContext()).inflate(R.layout.view_myview, this);
    }
}

我将相对布局换成线性布局了。然后看结果

Paste_Image.png

不一样了哦,这是为什么?我们只能从源码入手,来解释这个问题。由于已经有大神写的非常好了,所以我就不班门弄斧了。
我推荐一篇博客给大家<a href='http://blog.csdn.net/bboyfeiyu/article/details/45869393'>源码解析</a>
关键源码

         final View view = createViewFromTag(parent, name, attrs);  
               // 获取merge标签的parent  
               final ViewGroup viewGroup = (ViewGroup) parent;  
               // 获取布局参数  
               final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);  
               // 递归解析每个子元素  
               rInflate(parser, view, attrs, true);  
               // 将子元素直接添加到merge标签的parent view中  
               viewGroup.addView(view, params);  

原因就是,其实我们使用merge标签后,Layoutinflater解析遇到merge标签,直接解析成View,然后把解析出来的属性通过generateLayoutParams方法,变成我们熟悉的params,然后再添加到merge父容器里面去。父容器,在我们这里对应着MyView,MyView也就是LinearLayout,所以才会出现上面那样的效果,虽然,我们在merge标签里面写了below,但是LinearLayout是无法识别这个属性,还是按照默认的横向走向布局2个子View,导致出现了以上的情况,所以,使用merge还是有很大的局限性的.

我们要注意。要<b>自定义组合View会增加一层层级,所以,如果可以的话,我们要加上merge标签。而且保证我们在merge标签里面写的一些属性,要可以被merge标签的父容器识别才可以。</b>

相关文章

网友评论

  • a57ecf3aaaf2:include是不支持merge的
    b496178cdc84:这个我还没试,只是看到include里面也多余了层级 稍后试一试,然后修改一下。多谢

本文标题:这种情况,可能需要使用merge标签

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