Android优化ListView实践

ListView是Android中最常用的控件,通过适配器来进行数据适配然后显示出来,而其性能是个很
首页 新闻资讯 行业资讯 Android优化ListView实践

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

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

优化前的log截图:

优化后的log截图:

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

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

下面附上相关代码分析:

ListView中的每一个Item由一个ImageView 和一个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>
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

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

复制

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);     } }
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

  • 20.

  • 21.

  • 22.

  • 23.

  • 24.

  • 25.

  • 26.

  • 27.

  • 28.

  • 29.

  • 30.

  • 31.

  • 32.

  • 33.

  • 34.

  • 35.

  • 36.

然后custom Adapter,优化之前的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; }
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

  • 20.

优化之后的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;     } }
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

  • 20.

  • 21.

  • 22.

  • 23.

  • 24.

  • 25.

  • 26.

  • 27.

  • 28.

  • 29.

  • 30.

  • 31.

  • 32.

  • 33.

  • 34.

  • 35.

  • 36.

  • 37.

  • 38.

  • 39.

优化的大致思想就是:优化之前,每次加载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。