首先说一下产生问题的大致环境:
ReclerView中,child布局我直接使用的是android.R.layout.simple_list_item_1,也就是在onCreateViewHolder方法中我使用的View.inflate(context,android.R.layout.simple_list_item_1,xx)
然后我再onBindViewHolder方法中获取了child布局中的textview的参数getLayoutParams
不管View.inflate()第三个参数传null,还是parent,都报了异常…
那么?到底是什么原因呢?或者说,
View.inflate()第三个参数到底该传什么??
我们可以点进来看一下源码:
public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) {
LayoutInflater factory = LayoutInflater.from(context);
return factory.inflate(resource, root);
}
可以看出View.inflate()方法实际调用的是LayoutInflater.from(xx).inflate()方法,如下方法:
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
return inflate(resource, root, root != null);
}
可以看出,文章开篇问的第三个参数如果传null,则上面实际为:
return inflate(resource, null, false);
如果传的不是null,则:
return inflate(resource, root, true);
接下调用的是下面的方法:
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
final Resources res = getContext().getResources();
if (DEBUG) {
Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
+ Integer.toHexString(resource) + ")");
}
final XmlResourceParser parser = res.getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
synchronized (mConstructorArgs) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");
final Context inflaterContext = mContext;
final AttributeSet attrs = Xml.asAttributeSet(parser);
Context lastContext = (Context) mConstructorArgs[0];
mConstructorArgs[0] = inflaterContext;
View result = root;
try {
// Look for the root node.
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG &&
type != XmlPullParser.END_DOCUMENT) {
// Empty
}
if (type != XmlPullParser.START_TAG) {
throw new InflateException(parser.getPositionDescription()
+ ": No start tag found!");
}
final String name = parser.getName();
if (DEBUG) {
System.out.println("**************************");
System.out.println("Creating root view: "
+ name);
System.out.println("**************************");
}
if (TAG_MERGE.equals(name)) {
if (root == null || !attachToRoot) {
throw new InflateException(" can be used only with a valid "
+ "ViewGroup root and attachToRoot=true");
}
rInflate(parser, root, inflaterContext, attrs, false);
} else {
// Temp is the root view that was found in the xml
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
ViewGroup.LayoutParams params = null;
if (root != null) {
if (DEBUG) {
System.out.println("Creating params from root: " +
root);
}
// Create layout params that match root, if supplied
params = root.generateLayoutParams(attrs);
if (!attachToRoot) {
// Set the layout params for temp if we are not
// attaching. (If we are, we use addView, below)
temp.setLayoutParams(params);
}
}
if (DEBUG) {
System.out.println("-----> start inflating children");
}
// Inflate all children under temp against its context.
rInflateChildren(parser, temp, attrs, true);
if (DEBUG) {
System.out.println("-----> done inflating children");
}
// We are supposed to attach all the views we found (int temp)
// to root. Do that now.
if (root != null && attachToRoot) {
root.addView(temp, params);
}
// Decide whether to return the root that was passed in or the
// top view found in xml.
if (root == null || !attachToRoot) {
result = temp;
}
}
} catch (XmlPullParserException e) {
InflateException ex = new InflateException(e.getMessage());
ex.initCause(e);
throw ex;
} catch (Exception e) {
InflateException ex = new InflateException(
parser.getPositionDescription()
+ ": " + e.getMessage());
ex.initCause(e);
throw ex;
} finally {
// Don't retain static reference on context.
mConstructorArgs[0] = lastContext;
mConstructorArgs[1] = null;
}
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
return result;
}
}
可以分析:
root为null时,获取不到LayoutParams
root不为null时,通过方法generateLayoutParams()创建LayoutParams,但是你需要注意这么三行代码:
if (root != null && attachToRoot) {
root.addView(temp, params);
}
由于ReclerView会自动将child添加到它里面去,我们只需要实例化出来child就可以了,如果像上面这样,就是会添加两次,会报异常的。
按照上面分析的,使用View.inflate,第三个参数传null或者不是null都不行,到底怎么样呢?我们需要root不为null,但是又不能执行那三行代码,也就是attachToRoot为false,那么我们直接考虑LayoutInflater.from(xx).inflate(layout, parent, false),将它的第三个参数传false不就行了吗?反正最终调用的也是这个方法。没错,是这样的。
其实,我们用的是android.R.layout.simple_list_item_1布局,没有父布局:
如果是用的我们自己的布局的话,给Textview添加一个父布局,那么其实View.inflate(context,R.layout.item_view,null)的写法也是没有问题的。