This title is a bit exaggerated, but some usage of the LayoutInflater class does have some common mistakes during the use of Android Developers, at least the source code of so many small projects I have studied is basically using this class incorrectly. Today, I saw an article about LayoutInflater usage. I felt that I did not know enough about this class, so I simply read the source code of the LayoutInflater class, I have a new understanding of this class.
First, what is the LayoutInflater class used?
The most common method is the inflate method of LayoutInflater. This method reloads four call methods:
1. public View inflate (int resource, ViewGroup root)
2. public View inflate (int resource, ViewGroup root, boolean attachToRoot)
3. public View inflate (XmlPullParser parser, ViewGroup root)
4. public View inflate (XmlPullParser parser, ViewGroup root, boolean attachToRoot)
Among the four usage methods, we usually use the first method. The main function of the inflate method is to convert xml into a View object for Dynamic Layout creation. Although four methods are reloaded, the four methods are called in the fourth way. The fourth method is well understood. The internal implementation principle is to use the Pull parser to parse the Xml file and then return the View object.
Take the first form we often use as an example. Have you done this before rewriting the getView method of BaseAdapter?
public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = inflate(R.layout.item_row, null); } return convertView;}The inflate method has three parameters:
1. resource layout resource id
2. root-filled root View
3. Does attachToRoot bind the loaded View to the root view?
In this example, we set the root parameter to null, and the function is indeed implemented, but there is still a hidden danger. This method is not the correct position of inflate, next we will use a Demo to illustrate the disadvantages caused by such use.
First, we create a project like this.
There are three interfaces: one main interface and two test interfaces. In the layout file, the main interface is only responsible for page Jump. Both test interfaces are a simple Listview. The layout of items is shown as follows:
The corresponding layout file is as follows:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="60dp" android:background="@android:color/holo_orange_light" android:gravity="center" android:orientation="vertical" > <TextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="11" android:textColor="@android:color/black" android:textSize="22sp" /></LinearLayout>
The Code of OneActivity is as follows:
public class OneActivity extends Activity {private ListView list1;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_one);list1 = (ListView) findViewById(R.id.list1);list1.setAdapter(new MyAdapter(this));}private class MyAdapter extends BaseAdapter {private LayoutInflater inflater;MyAdapter(Context context) {inflater = LayoutInflater.from(context);}@Overridepublic int getCount() {return 20;}@Overridepublic Object getItem(int position) {return position;}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {if (convertView == null) {convertView = inflater.inflate(R.layout.item_list, null);}TextView tv = (TextView) convertView.findViewById(R.id.tv);tv.setText(position+"");return convertView;}}}
The TwoActivity code is as follows:
public class TwoActivity extends Activity {private ListView list2;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_two);list2 = (ListView) findViewById(R.id.list2);list2.setAdapter(new MyAdapter(this));}private class MyAdapter extends BaseAdapter {private LayoutInflater inflater;MyAdapter(Context context) {inflater = LayoutInflater.from(context);}@Overridepublic int getCount() {return 20;}@Overridepublic Object getItem(int position) {return position;}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {if (convertView == null) {convertView = inflater.inflate(R.layout.item_list, parent,false);}TextView tv = (TextView) convertView.findViewById(R.id.tv);tv.setText(position + "");return convertView;}}}
The key difference between the two files is one sentence,
In the getView method, OneActivity is
ConvertView = inflater. inflate (R. layout. item_list, null );
In the getView method, TwoActivity is
ConvertView = inflater. inflate (R. layout. item_list, parent, false );
Let's take a look at the display effect first, then let's talk about the difference between the two.
OneActivity Effect
Display Effect of TwoActivity
We can clearly see that using the first method, the height setting of the root layout 60dp does not work, and the system still loads the package content. Why is this effect? Find the answer from the source code that requires the inflate method.
First, method 1 source code implementation
public View inflate(XmlPullParser parser, ViewGroup root) { return inflate(parser, root, root != null); }
When method 1 is used and the second parameter is null, the following method is called by default, and attachToRoot is false.
public View inflate(int resource, ViewGroup root, boolean attachToRoot) { if (DEBUG) System.out.println("INFLATING from resource: " + resource); XmlResourceParser parser = getContext().getResources().getLayout(resource); try { return inflate(parser, root, attachToRoot); } finally { parser.close(); } }
In this method, the pull parser converts the resource id into an XmlResourceParser object and passes it to the fourth method. Therefore, we need to focus on how the fourth method is implemented.
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); } else { // Temp is the root view that was found in the xml View temp; if (TAG_1995.equals(name)) { temp = new BlinkLayout(mContext, attrs); } else { temp = createViewFromTag(root, name, 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 rInflate(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 (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; } }
The code is long, so we focus on the following code.
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); } }
The code means that when the passed root parameter is not empty and the attachToRoot parameter is false, that is, the TwoActivity implementation method above, A LayoutParams parameter is set for temp. So what does temp do?
<pre name="code" class="java">// 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; }
Now, we should understand that when the passed root parameter is not null and the third parameter is false, the temp parameter is added to the root parameter, root is returned as the final return value. When the root parameter is set to null, the temp object of the LayoutParams parameter is not set and is returned as the return value.
Therefore, we can draw the following conclusion:
1. if convertView = inflater is used. inflate (R. layout. item_list, null); fill the view. The layout_XX attribute of the Root View in the item layout will be ignored and set to the default Package content method.
2. if we want to ensure that the parameters in the item view are not changed, we need to use convertView = inflater. inflate (R. layout. item_list, parent, false); fill the view in this way
3. In addition to this method, we can also set the Root View of the item layout as the package content, and then set the internal control height and other attributes so that the display mode will not be modified.
Finally, let's go to http://blog.jobbole.com/72156 /.