Android development: optimize the analysis of ListView practices
After reading some vogella articles, I found that the performance optimization of android listview is very interesting. So I practiced it. After optimization, the performance is indeed improved a lot!
First look at the comparison before and after optimization:
Logs before optimization:
Optimized log:
In addition, ANR may occur before optimization in the Process of non-stop scrolling ListView, which is particularly easy to reproduce on AVD:
Then, the optimization looks very smooth, and the corresponding log is attached:
The relevant code analysis is attached below:
Each Item in ListView is composed of an ImageView and a TextView.
Layout:
- <? Xml version = "1.0" encoding = "UTF-8"?>
- <LinearLayout xmlns: android = "http://schemas.android.com/apk/res/android"
- Android: layout_width = "fill_parent"
- Android: layout_height = "fill_parent"
- Android: orientation = "horizontal">
- <ImageView android: id = "@ + id/imageView"
- Android: layout_width = "wrap_content"
- Android: layout_height = "fill_parent"/>"
- <TextView android: id = "@ + id/textView"
- Android: layout_width = "wrap_content"
- Android: layout_height = "fill_parent"
- Android: layout_marginLeft = "15dp"
- Android: gravity = "center_vertical"/>
- </LinearLayout>
The Activity is inherited from ListActivity. I intentionally added Item to facilitate testing and the effect is more obvious:
- Public class ListViewDemo extends ListActivity {
- Private final String [] mItems = new String [] {"Android", "iPhone ",
- "WindowsMobile", "Blackberry", "WebOS", "Ubuntu", "Windows7 ",
- "Max OS x", "Linux", "OS/2", "Ubuntu", "Windows7", "Max OS X ",
- "Linux", "OS/2", "Ubuntu", "Windows7", "Max OS x", "Linux", "OS/2 ",
- "Ubuntu", "Windows7", "Max OS x", "Linux", "OS/2", "Ubuntu ",
- "Windows7", "Max OS x", "Linux", "OS/2", "Ubuntu", "Windows7 ",
- "Max OS x", "Linux", "OS/2", "Ubuntu", "Windows7", "Max OS X ",
- "Linux", "OS/2", "Ubuntu", "Windows7", "Max OS x", "Linux", "OS/2 ",
- "Ubuntu", "Windows7", "Max OS x", "Linux", "OS/2", "Ubuntu ",
- "Windows7", "Max OS x", "Linux", "OS/2", "Ubuntu", "Windows7 ",
- "Max OS x", "Linux", "OS/2", "Ubuntu", "Windows7", "Max OS X ",
- "Linux", "OS/2", "Ubuntu", "Windows7", "Max OS x", "Linux", "OS/2 ",
- "Ubuntu", "Windows7", "Max OS x", "Linux", "OS/2", "Ubuntu ",
- "Windows7", "Max OS x", "Linux", "OS/2", "Ubuntu", "Windows7 ",
- "Max OS x", "Linux", "OS/2", "Ubuntu", "Windows7", "Max OS X ",
- "Linux", "OS/2", "Ubuntu", "Windows7", "Max OS x", "Linux", "OS/2 ",
- "Ubuntu", "Windows7", "Max OS x", "Linux", "OS/2", "Ubuntu ",
- "Windows7", "Max OS x", "Linux", "OS/2", "Ubuntu", "Windows7 ",
- "Max OS x", "Linux", "OS/2", "Ubuntu", "Windows7", "Max OS X ",
- "Linux", "OS/2", "Ubuntu", "Windows7", "Max OS x", "Linux", "OS/2 ",
- "Ubuntu", "Windows7", "Max OS x", "Linux", "OS/2", "Ubuntu ",
- "Windows7", "Max OS x", "Linux", "OS/2", "Ubuntu", "Windows7 ",
- "Max OS x", "Linux", "OS/2", "Ubuntu", "Windows7", "Max OS X ",
- "Linux", "OS/2", "Ubuntu", "Windows7", "Max OS x", "Linux", "OS/2 ",
- "Ubuntu", "Windows7", "Max OS x", "Linux", "OS/2", "Ubuntu ",
- "Windows7", "Max OS x", "Linux", "OS/2", "Ubuntu", "Windows7 ",
- "Max OS x", "Linux", "OS/2", "Ubuntu", "Windows7", "Max OS X ",
- "Linux", "OS/2", "Ubuntu", "Windows7", "Max OS x", "Linux", "OS/2 "};
- @ Override
- Public void onCreate (Bundle savedInstanceState ){
- Super. onCreate (savedInstanceState );
- ListViewArrayAdapter adapter = new ListViewArrayAdapter (this, mItems );
- GetListView (). setAdapter (adapter );
- }
- }
Then, use the M Adapter to optimize the previous adapter:
- @ Override
- Public View getView (int position, View convertView, ViewGroup parent ){
- Long start = System. currentTimeMillis ();
- LayoutInflater inflater = (LayoutInflater) mContext. getLayoutInflater ();
- View rowView = inflater. inflate (mViewResourceId, parent, false );
- TextView textView = (TextView) rowView
- . FindViewById (mTextViewResourceId );
- ImageView imageView = (ImageView) rowView
- . FindViewById (mImageViewResourceId );
- TextView. setText (mNames [position]);
- String s = mNames [position];
- If (s. startsWith ("Windows7") | s. startsWith ("iPhone ")){
- ImageView. setImageResource (R. drawable. no );
- } Else {
- ImageView. setImageResource (R. drawable. yes );
- }
- Log. v ("jerikc", "cost time =" + (System. currentTimeMillis ()-start ));
- Return rowView;
- }
The optimized Adapter:
- Public class ListViewArrayAdapter extends ArrayAdapter <String> {
- Private final Activity mContext;
- Private final String [] mNames;
- Private final static int mViewResourceId = R. layout. text_image_row_layout;
- Private final static int mTextViewResourceId = R. id. textView;
- Private final static int mImageViewResourceId = R. id. imageView;
- Static class ViewHolder {
- Public TextView text;
- Public ImageView image;
- }
- Public ListViewArrayAdapter (Activity context, String [] names ){
- Super (context, mViewResourceId, names );
- This. mContext = context;
- This. mNames = names;
- }
- @ Override
- Public View getView (int position, View convertView, ViewGroup parent ){
- Long start = System. currentTimeMillis ();
- View rowView = convertView;
- If (rowView = null ){
- LayoutInflater inflater = mContext. getLayoutInflater ();
- RowView = inflater. inflate (mViewResourceId, null );
- ViewHolder viewHolder = new ViewHolder ();
- ViewHolder. text = (TextView) rowView. findViewById (mTextViewResourceId );
- ViewHolder. image = (ImageView) rowView. findViewById (mImageViewResourceId );
- RowView. setTag (viewHolder );
- }
- ViewHolder holder = (ViewHolder) rowView. getTag ();
- String s = mNames [position];
- Holder. text. setText (s );
- If (s. startsWith ("Windows7") | s. startsWith ("iPhone ")){
- Holder. image. setImageResource (R. drawable. no );
- } Else {
- Holder. image. setImageResource (R. drawable. yes );
- }
- Log. v ("jerikc", "cost time =" + (System. currentTimeMillis ()-start ));
- Return rowView;
- }
- }
The general idea of optimization is: before optimization, each time you load an item, you need to load the layout file and generate a new row View object, then we can find the corresponding ImageView and TextView through the View. As we know, loading layout files is time-consuming, especially when operations are frequent, therefore, ANR may occur.
Therefore, we can reuse invisible row View objects. In Android, when it decides to make the row View object invisible, it allows the convertView parameter in the getView method to reuse the previously invisible row View object.
During the optimization process, when loading for the first time, we need to save the relevant data, and the View has a method setTag, which can be used to save some data structures. A row View object consists of ImageView and TextView spaces. Therefore, a ViewHolder is defined to save ImageView and TextView objects. In the reuse process, you only need to modify their values, instead of the findViewById.