LayoutInflater.inflater()方法及参数源码分析
inflate加载布局的时候有四个方法提供,分别如下
平常主要用到的还是前两个。
下面从源码角度分析一下这四个方法的区别和用法。
1、方法1
public View inflate(@LayoutResint resource, @Nullable ViewGroup root) {
return inflate(resource, root, root != null);
}
resource:需要加载布局文件的id,意思是需要将这个布局文件中加载到Activity中来操作。
root:需要附加到resource资源文件的根控件,什么意思呢,就是inflate()会返回一个View对象,如果第三个参数attachToRoot
为true,就将这个root作为根对象返回,否则仅仅将这个root对象的LayoutParams属性附加到resource对象的根布局对象
上(方法4的红色背景代码区域就是LayoutPara马上参数),也就是布局文件resource的最外层的View上。
2、方法2
public View inflate(@LayoutResint resource, @Nullable ViewGroup root, boolean attachToRoot) {
final Resources res =getContext().getResources();if (DEBUG) {
Log.d(TAG, "INFLATINGfrom resource: \"" + res.getResourceName(resource) + "\"("
+ Integer.toHexString(resource)+ ")");
}
final XmlResourceParserparser = res.getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
attachToRoot:是否将root附加到布局文件的根视图上。
如果没有传递attachToRoot参数,则根据root是否为null判断。
3、方法3
public View inflate(XmlPullParserparser, @Nullable ViewGroup root) {
return inflate(parser, root, root != null);
}
4、方法4
public View inflate(XmlPullParserparser, @Nullable ViewGroup root, boolean attachToRoot) {
……
if (root != null) {
if (DEBUG) {
System.out.println("Creatingparams from root: " +
root);
}
// Create layout params that matchroot, if supplied
params =root.generateLayoutParams(attrs);
if (!attachToRoot) {
// Set the layout params for temp if we arenot
// attaching. (If we are, we useaddView, below)
temp.setLayoutParams(params);
}
}
…….
// We are supposedto attach all the views we found (int temp)
// to root. Do that now.
if (root != null && attachToRoot) {
root.addView(temp, params);
}
}
从4个方法的源码可以看出,方法1实际调用的是方法2,方法2和方法3实际调用的都是方法4。也就是方法4是最终被调用的。
方法4中有个参数params,是根据root!=null条件下实例化的,如果root传递的是null,那么params就为空。在适配器中使用View.inflate(Context context,int resource, ViewGroup root)实例化布局文件时,经常出现的一个NullPointException—LayoutParams为空error就是这个问题引起的,下面详细说一下。
View.inflate(Contextcontext,int resource, ViewGroup root)实例化布局文件时,当root为null时引起的LayoutParams为null异常问题 和root不为null时引起的The specified child already has a parent.You must call removeView() onthe child’s parent first问题。
查看inflate源码如下:
public static View inflate(Contextcontext, @LayoutRes int resource, ViewGroup root) {
LayoutInflater factory =LayoutInflater.from(context);
return factory.inflate(resource, root);
}
实质是调用的上面的方法1。
此处我们来分别看下View.inflate(this,resource,root);和View.inflate(this,resource,null);root为空和不为空都会引起错误原因
(1). View.inflate(this,resource,null);root为null时,根据源码流程—>调用方法1.inflate(resource, null);—>方法2 inflate(resource, null, false); -à方法4 inflate(parser, null, false); 查看方法4中红色背景区域代码,判断条件是root!=null,,而此时root==null,,所以就会报出LayoutParams为null的错误。
(2). View.inflate(this,resource,root);root不为null时,根据源码流程—>调用方法1.inflate(resource, root);—>方法2 inflate(resource, root,true); -à方法4 inflate(parser,root,true); 查看方法4中灰色背景区域代码,判断条件是if (root != null &&attachToRoot) ,,判断条件为true,。执行root.addView(temp,params); 把布局和布局参数添加到了根布局,此时就会报出The specified childalready has a parent.You must call removeView() on the child’s parent first问题。
为什么会重复加载呢,因为RecyclerView/ListView会自动将child添加到它的布局里面去,这里attachToRoot如果为true,就会出现重复加载的问题。
解决这两个问题的方法就是,root不为null,但是要传递attachToRoot参数为false。