代码改变世界

android listview 优化

2013-04-03 10:02  三戒1993  阅读(161)  评论(0编辑  收藏  举报

在看了一些vogella的文章之后,发现关于android listview性能优化这一段很有意思,于是实践了一下,经过优化,性能确实提升不少!

先看看优化前和优化后的比较:

优化前的log截图:

优化后的log截图:

并且,在不停滚动ListView的过程中,优化之前会出现ANR现象,在AVD上特别容易复现:

然后,优化后显得很流畅,附上对于的log截图:

下面附上相关代码分析:

ListView中的每一个Item由一个ImageView 和一个TextView组成

Layout:

01 <?xml version="1.0" encoding="utf-8"?>
02 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
03         android:layout_width="fill_parent"
04         android:layout_height="fill_parent"
05         android:orientation="horizontal" >
06          
07         <ImageView android:id="@+id/imageView"
08             android:layout_width="wrap_content"
09             android:layout_height="fill_parent" />"
10         <TextView android:id="@+id/textView"
11             android:layout_width="wrap_content"
12             android:layout_height="fill_parent"
13             android:layout_marginLeft="15dp"
14             android:gravity="center_vertical" />
15 </LinearLayout>


Activity继承自ListActivity,我故意增加了Item,方便测试,效果更明显:

01 public class ListViewDemo extends ListActivity{
02  
03     private final String[] mItems = new String[] { "Android""iPhone",
04             "WindowsMobile""Blackberry""WebOS""Ubuntu""Windows7",
05             "Max OS X""Linux""OS/2""Ubuntu""Windows7""Max OS X",
06             "Linux""OS/2""Ubuntu""Windows7""Max OS X""Linux""OS/2",
07             "Ubuntu""Windows7""Max OS X""Linux""OS/2""Ubuntu",
08             "Windows7""Max OS X""Linux""OS/2""Ubuntu""Windows7",
09             "Max OS X""Linux""OS/2""Ubuntu""Windows7""Max OS X",
10             "Linux""OS/2""Ubuntu""Windows7""Max OS X""Linux""OS/2",
11             "Ubuntu""Windows7""Max OS X""Linux""OS/2""Ubuntu",
12             "Windows7""Max OS X""Linux""OS/2""Ubuntu""Windows7",
13             "Max OS X""Linux""OS/2""Ubuntu""Windows7""Max OS X",
14             "Linux""OS/2""Ubuntu""Windows7""Max OS X""Linux""OS/2",
15             "Ubuntu""Windows7""Max OS X""Linux""OS/2""Ubuntu",
16             "Windows7""Max OS X""Linux""OS/2""Ubuntu""Windows7",
17             "Max OS X""Linux""OS/2""Ubuntu""Windows7""Max OS X",
18             "Linux""OS/2""Ubuntu""Windows7""Max OS X""Linux""OS/2",
19             "Ubuntu""Windows7""Max OS X""Linux""OS/2""Ubuntu",
20             "Windows7""Max OS X""Linux""OS/2""Ubuntu""Windows7",
21             "Max OS X""Linux""OS/2""Ubuntu""Windows7""Max OS X",
22             "Linux""OS/2""Ubuntu""Windows7""Max OS X""Linux""OS/2",
23             "Ubuntu""Windows7""Max OS X""Linux""OS/2""Ubuntu",
24             "Windows7""Max OS X""Linux""OS/2""Ubuntu""Windows7",
25             "Max OS X""Linux""OS/2""Ubuntu""Windows7""Max OS X",
26             "Linux""OS/2""Ubuntu""Windows7""Max OS X""Linux""OS/2",
27             "Ubuntu""Windows7""Max OS X""Linux""OS/2""Ubuntu",
28             "Windows7""Max OS X""Linux""OS/2""Ubuntu""Windows7",
29             "Max OS X""Linux""OS/2""Ubuntu""Windows7""Max OS X",
30             "Linux""OS/2""Ubuntu""Windows7""Max OS X""Linux""OS/2" };
31     @Override
32     public void onCreate(Bundle savedInstanceState) {
33         super.onCreate(savedInstanceState);
34         ListViewArrayAdapter adapter = new ListViewArrayAdapter(this, mItems);
35         getListView().setAdapter(adapter);
36     }
37 }


然后custom Adapter,优化之前的adapter:

01 @Override
02     public View getView(int position, View convertView, ViewGroup parent) {
03         long start = System.currentTimeMillis();
04         LayoutInflater inflater = (LayoutInflater) mContext.getLayoutInflater();
05         View rowView = inflater.inflate(mViewResourceId, parent, false);
06         TextView textView = (TextView) rowView
07                 .findViewById(mTextViewResourceId);
08         ImageView imageView = (ImageView) rowView
09                 .findViewById(mImageViewResourceId);
10         textView.setText(mNames[position]);
11         String s = mNames[position];
12         if (s.startsWith("Windows7") || s.startsWith("iPhone")) {
13             imageView.setImageResource(R.drawable.no);
14         else {
15             imageView.setImageResource(R.drawable.yes);
16         }
17              
18         Log.v("jerikc","cost time = " + (System.currentTimeMillis() - start));
19         return rowView;
20     }


优化之后的Adapter:

01 public class ListViewArrayAdapter extends ArrayAdapter<String>{
02  
03     private final Activity mContext;
04     private final String[] mNames;
05     private final static int mViewResourceId = R.layout.text_image_row_layout;
06     private final static int mTextViewResourceId = R.id.textView;
07     private final static int mImageViewResourceId = R.id.imageView;
08     static class ViewHolder {
09         public TextView text;
10         public ImageView image;
11     }
12      
13     public ListViewArrayAdapter(Activity context, String[] names) {
14         super(context, mViewResourceId, names);
15         this.mContext = context;
16         this.mNames = names;
17     }
18      
19     @Override
20     public View getView(int position, View convertView, ViewGroup parent) {
21         long start = System.currentTimeMillis();
22         View rowView = convertView;
23         if (rowView == null) {
24             LayoutInflater inflater = mContext.getLayoutInflater();
25             rowView = inflater.inflate(mViewResourceId, null);
26             ViewHolder viewHolder = new ViewHolder();
27             viewHolder.text = (TextView) rowView.findViewById(mTextViewResourceId);
28             viewHolder.image = (ImageView) rowView.findViewById(mImageViewResourceId);
29             rowView.setTag(viewHolder);
30         }
31          
32         ViewHolder holder = (ViewHolder) rowView.getTag();
33         String s = mNames[position];
34         holder.text.setText(s);
35         if (s.startsWith("Windows7") || s.startsWith("iPhone")) {
36             holder.image.setImageResource(R.drawable.no);
37         else {
38             holder.image.setImageResource(R.drawable.yes);
39         }
40              
41         Log.v("jerikc","cost time = " + (System.currentTimeMillis() - start));
42         return rowView;
43     }
44 }


优化的大致思想就是:优化之前,每次加载item的时候,都要加载一下布局文件,然后生成一个新的row View对象,然后通过View找到对应的ImageView和TextView,正如我们所知道的那样,加载布局文件时很耗时的,特别是在操作比较频繁情况下,这是不可忍受的,所以会导致ANR现象。

因此,我们可以重复利用已不可见的row View对象。Android中,当它决定让row View对象不可见的时候,它允许通过getView方法中的convertView参数来重复利用刚刚不可见的row View对象。

在优化的过程中,第一次加载的时候,我们需要把相关的数据保存起来,而View有一个方法setTag,该方法可用来保存一些数据结构。我们一个row View对象是由ImageView和TextView空间组成的,因此定义一个ViewHolder来保存ImageView和TextView对象。在重复利用的过程中,只需简单修改它们的值,而不用再次findViewById

关于findViewById耗时的分析,可参考:

http://www.cnblogs.com/over140/archive/2011/03/23/1991100.html