Android进阶之View.inflate和LayoutInflater.inflate方法区别

https://blog.csdn.net/chenliguan/article/details/82314122?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&dist_request_id=&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.control
1 LayoutInflater用于加载布局
LayoutInflater用于加载布局的。加载布局的任务通常都是在Activity中调用setContentView()方法来完成的。其实setContentView()方法的内部也是使用LayoutInflater来加载布局的,只不过这部分源码是内部的。先看下LayoutInflater的基本用法,首先需要获取到LayoutInflater的实例,有两种方法可以获取到:

// 第一种写法如下:
LayoutInflater layoutInflater = LayoutInflater.from(context);

// 还有另外一种写法也可以完成同样的效果:
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// 得到了LayoutInflater的实例之后就可以调用它的inflate()方法来加载布局了,如下所示:
layoutInflater.inflate(resourceId, root);

2 View.inflate和LayoutInflater.inflate效果的区别
(1)平时Recyclerview加载item中,adapter的getView方法中,我们经常用到LayoutInflater.inflate这样的方法来加载布局xml,平时一直就是这么用的,也没什么疑问。

LayoutInflater.from(mContext).inflate(R.layout.item_consume_recharge_record, parent, false);
1
(2)一次在加载布局时,使用了如下的方法View.inflate加载布局:

@Override
public ConsumeRechargeRecordViewHolder onCreateViewHolder_(ViewGroup parent, int viewType) {
    View itemView = View.inflate(mContext, R.layout.item_consume_recharge_record, null);
    return new ConsumeRechargeRecordViewHolder(itemView);
}

得到的效果如下,没有将item的布局文件最外层的所有layout属性设置:

(3)尝试多次调整后,使用LayoutInflater.inflate来加载布局,代码以及得到的效果截图如下,将item的布局文件最外层的所有layout属性设置(有边框):

@Override
public ConsumeRechargeRecordViewHolder onCreateViewHolder_(ViewGroup parent, int viewType) {
    View itemView = LayoutInflater.from(mContext).inflate(R.layout.item_consume_recharge_record, parent, false);
    return new ConsumeRechargeRecordViewHolder(itemView);
}
 


3 原理分析
3.1 View.inflate与LayoutInflater.inflate的区别
虽然已经实现了效果,但心中的疑惑(为什么是这样的对比效果?)一直没解开,非常的难受,周末沉下心来研究一番,终于知道的原因所在,耶。
(1)首先看View.inflate的源码:

// View.inflate(context, resource, root)
public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) {
    LayoutInflater factory = LayoutInflater.from(context);
    return factory.inflate(resource, root); // 其实内部也是用LayoutInflater实现的:
}

(2)LayoutInflater.inflate的源码:

// LayoutInflater.inflate(resource, root)
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
    return inflate(resource, root, root != null);
}

3.2 Inflate的三个参数(int resource, ViewGroup root, boolean attachToRoot)分析
(1)那对于Inflate的三个参数(int resource, ViewGroup root, boolean attachToRoot)是什么意思呢?

(2)先看源码:


public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
        synchronized (mConstructorArgs) {
        final AttributeSet attrs = Xml.asAttributeSet(parser);
        mConstructorArgs[0] = mContext;
        View result = root;
        try {
            int type;
            while ((type = parser.next()) != XmlPullParser.START_TAG &&
                    type != XmlPullParser.END_DOCUMENT) {
            }
            if (type != XmlPullParser.START_TAG) {
                throw new InflateException(parser.getPositionDescription()
                        + ": No start tag found!");
            }
            final String name = parser.getName();
            if (TAG_MERGE.equals(name)) {
                if (root == null || !attachToRoot) {
                    throw new InflateException("merge can be used only with a valid "
                            + "ViewGroup root and attachToRoot=true");
                }
                rInflate(parser, root, attrs);
            } else {
                View temp = createViewFromTag(name, attrs);
                ViewGroup.LayoutParams params = null;
                if (root != null) {
                    params = root.generateLayoutParams(attrs);
                    if (!attachToRoot) {
                        temp.setLayoutParams(params);
                    }
                }
                rInflate(parser, temp, attrs);
                if (root != null && attachToRoot) {
                    root.addView(temp, params);
                }
                if (root == null || !attachToRoot) {
                    result = temp;
                }
            }
        } catch (XmlPullParserException e) {
            InflateException ex = new InflateException(e.getMessage());
            ex.initCause(e);
            throw ex;
        } catch (IOException e) {
            InflateException ex = new InflateException(
                    parser.getPositionDescription()
                    + ": " + e.getMessage());
            ex.initCause(e);
            throw ex;
        }
        return result;
    }
}

(3)核心部分源码如下,具体分析源码的逻辑:

    View temp = createViewFromTag(name, attrs);
    // 布局文件最外层的layout属性
    ViewGroup.LayoutParams params = null;
    if (root != null) {
        params = root.generateLayoutParams(attrs);
        // 3.root不为null,attachToRoot设为false,则会将布局文件最外层的所有layout属性进行设置
        if (!attachToRoot) {
            temp.setLayoutParams(params);
        }
    }
    rInflate(parser, temp, attrs);
    // 2.root不为null,attachToRoot设为true,则会给布局文件指定一个父布局,即root
    if (root != null && attachToRoot) {
        root.addView(temp, params);
    }
    // 1.root为null,attachToRoot将失去作用,则布局文件设置任何值都没有意义,仅仅是解析布局文件的子View
    if (root == null || !attachToRoot) {
        result = temp;
    }

(4)结论:

1. 如果root为null,attachToRoot将失去作用,则布局文件最外层设置任何值都没有意义,仅仅是解析布局文件的子View。
2. 如果root不为null,attachToRoot设为true,则会给布局文件指定一个父布局,即root。(merge作为父布局标签为什么需要attachToRoot设为true的原因)
3. 如果root不为null,attachToRoot设为false,则会将布局文件最外层的所有layout属性进行设置,当该view被添加到父view当中时,这些layout属性会自动生效。
4. 在不设置attachToRoot参数的情况下,如果root不为null,attachToRoot参数默认为true;如果root为null,attachToRoot参数为false。

4 为什么有区别?
(1)所以,当使用View.inflate(mContext, xml, null)时,传入的root为null,attachToRoot为false,attachToRoot将失去作用,则布局文件最外层设置任何值都没有意义,仅仅是解析布局文件的子View,所以得到的效果仅仅是item内部子View。
(2)那又有疑问了,设置View.inflate(mContext, xml, parent)不就可以了吗?结果是程序崩溃,为什么?
(3)因为Recyclerview中adapter的getView方法加载的布局已经设置了父布局,不需要指定一个父布局——第2点,只需要将布局文件最外层的所有layout属性进行设置——第3点,所以使用如下的方法加载生效:

View itemView = LayoutInflater.from(mContext).inflate(R.layout.item_consume_recharge_record, parent, false);
1
5 学习链接
Android LayoutInflater原理分析,带你一步步深入了解View(一)

View.inflate和LayoutInflater的inflate方法区别

 

View.inflate()和LayoutInflater.inflate()的区别
编码之路
 5536
一、LayoutInflater.inflate() 该方法适用于所有布局填充的的场景,但使用前需要先实例化LayoutInflater对象 1. 获取LayoutInflater实例 getLayoutInflater(); 这个方法可以在Activity和Fragment中使用,不过在Fragment中使用时,要传入一个bundle参数 // Activity中使用 LayoutInflater layoutInflater = getLayoutInflater(); // Fragment中使用
Android高手进阶教程(五)之----Android 中LayoutInflater的使用!
Android_Tutor的专栏
 2万+
大家好我们这一节讲的是LayoutInflater的使用,在实际开发种LayoutInflater这个类还是非常有用的,它的作用类似于findViewById(), 不同点是LayoutInflater是用来找layout下xml布局文件,
————————————————
版权声明:本文为CSDN博主「小冠^-^」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/chenliguan/article/details/82314122

你可能感兴趣的:(Android进阶之View.inflate和LayoutInflater.inflate方法区别)