@linux1s1s
2019-03-12T03:13:22.000000Z
字数 7809
阅读 2414
AndroidView 2016-04
/*** Inflate a new view hierarchy from the specified xml resource. Throws* {@link InflateException} if there is an error.** @param resource ID for an XML layout resource to load (e.g.,* <code>R.layout.main_page</code>)* @param root Optional view to be the parent of the generated hierarchy.* @return The root View of the inflated hierarchy. If root was supplied,* this is the root View; otherwise it is the root of the inflated* XML file.*/public View inflate(int resource, ViewGroup root) {return inflate(resource, root, root != null);}/*** Inflate a new view hierarchy from the specified xml node. Throws* {@link InflateException} if there is an error. ** <p>* <em><strong>Important</strong></em> For performance* reasons, view inflation relies heavily on pre-processing of XML files* that is done at build time. Therefore, it is not currently possible to* use LayoutInflater with an XmlPullParser over a plain XML file at runtime.** @param parser XML dom node containing the description of the view* hierarchy.* @param root Optional view to be the parent of the generated hierarchy.* @return The root View of the inflated hierarchy. If root was supplied,* this is the root View; otherwise it is the root of the inflated* XML file.*/public View inflate(XmlPullParser parser, ViewGroup root) {return inflate(parser, root, root != null);}/*** Inflate a new view hierarchy from the specified xml resource. Throws* {@link InflateException} if there is an error.** @param resource ID for an XML layout resource to load (e.g.,* <code>R.layout.main_page</code>)* @param root Optional view to be the parent of the generated hierarchy (if* <em>attachToRoot</em> is true), or else simply an object that* provides a set of LayoutParams values for root of the returned* hierarchy (if <em>attachToRoot</em> is false.)* @param attachToRoot Whether the inflated hierarchy should be attached to* the root parameter? If false, root is only used to create the* correct subclass of LayoutParams for the root view in the XML.* @return The root View of the inflated hierarchy. If root was supplied and* attachToRoot is true, this is root; otherwise it is the root of* the inflated XML file.*/public View inflate(int resource, 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();}}/*** Inflate a new view hierarchy from the specified XML node. Throws* {@link InflateException} if there is an error.* <p>* <em><strong>Important</strong></em> For performance* reasons, view inflation relies heavily on pre-processing of XML files* that is done at build time. Therefore, it is not currently possible to* use LayoutInflater with an XmlPullParser over a plain XML file at runtime.** @param parser XML dom node containing the description of the view* hierarchy.* @param root Optional view to be the parent of the generated hierarchy (if* <em>attachToRoot</em> is true), or else simply an object that* provides a set of LayoutParams values for root of the returned* hierarchy (if <em>attachToRoot</em> is false.)* @param attachToRoot Whether the inflated hierarchy should be attached to* the root parameter? If false, root is only used to create the* correct subclass of LayoutParams for the root view in the XML.* @return The root View of the inflated hierarchy. If root was supplied and* attachToRoot is true, this is root; otherwise it is the root of* the inflated XML file.*/public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {synchronized (mConstructorArgs) {Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");final AttributeSet attrs = Xml.asAttributeSet(parser);Context lastContext = (Context)mConstructorArgs[0];mConstructorArgs[0] = mContext;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("<merge /> can be used only with a valid "+ "ViewGroup root and attachToRoot=true");}rInflate(parser, root, attrs, false, false);} else {// Temp is the root view that was found in the xmlfinal View temp = createViewFromTag(root, name, attrs, false);ViewGroup.LayoutParams params = null;if (root != null) {if (DEBUG) {System.out.println("Creating params from root: " +root);}// Create layout params that match root, if suppliedparams = 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 temprInflate(parser, temp, attrs, true, 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 (IOException 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;}}
回顾一下上面刚开始提及的几个问题。
- inflate()方法中第三个Boolean型参数实现什么功能
- 请举例常见的几种情况
- 什么情况下应该设置为true,什么情况下应该设置为false
// 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);}
所以小结下来就是这样:
Button button = (Button) inflater.inflate(R.layout.custom_button, mLinearLayout, false);mLinearLayout.addView(button);
===========================等价于==========================
Button button = (Button) inflater.inflate(R.layout.custom_button, mLinearLayout, true);
@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {rootView = inflater.inflate(R.layout.webview_style_inner, container, false);rootWebView = (FanliWebviewContainer) rootView.findViewById(R.id.webviewContainer);return rootView;}
上面的第三行很多人也会这么写
rootView = inflater.inflate(R.layout.webview_style_inner, null);
问题:这两种写法,你更倾向于哪种,有什么区别?为什么大部分情况下这两种写法都能正常工作,而参数取为true则直接抛
IllegalStateException异常。
如果ViewGroup传值为null,最起码的区别就是下面的警告

那么出现这种警告以后,我们有必要甩它吗?如果不care会怎样?
你的App不会挂掉,但是可能会出现异常。当你的子View没有正确的LayoutParams时,它会自己通过generateDefaultLayoutParams)计算。
你可能并不想要这些默认的LayoutParams。你在XML指定的LayoutParams会被忽略。我们可能已经指定了子View要填充父元素的宽度,但父View又wrap_content导致最终的View小很多。
所以很多人随手将ViewGroup故意置为null,为将来的bug埋下隐患,所以这里的原则就是有ViewGroup的地方还是老老实实的传下去。
问题:上面留下来的,为什么第三个参数传值为true会抛
IllegalStateException异常?
原因是Fragment中将View添加到Activity,是由FragmentManager来负责添加,删除,替换等,所以这些都是由FragmentManager来管理的,不需要我们手动添加View到ViewGroup,如果手动去添加,势必会导致重复添加子View,所以会抛出IllegalStateException异常就好解释了。
那么还有其他情况和此种情况类似的吗? 这里仅仅举个栗子,在BaseAdapter中getView()方法里面
@Overridepublic View getView(int position, View convertView, ViewGroup parent) {ViewHolder holder;if (convertView == null) {holder = new ViewHolder();convertView = mInflater.inflate(R.layout.list_fanli_record_item, parent, false);holder.creatTimeView = (TangFontTextView) convertView.findViewById(R.id.create_time);convertView.setTag(holder);} else {holder = (ViewHolder) convertView.getTag();}return convertView;}
上面是ListView的数据适配器Adapter中适配View并重用View的典型代码,其中L7就符合上面Fragment的情况。ListView负责决定什么时候展示它的子View,这个不由我们决定。所以小结一下结论就是:在任何我们不负责将View添加进ViewGroup的情况下都应该将attachToRoot设置为false。
总结一下结论如下:
IllegalStateException异常。