Android优化ListView实践

移动开发 Android
ListView是Android中最常用的控件,通过适配器来进行数据适配然后显示出来,而其性能是个很值得研究的话题。本文与你一起探讨Google I/O提供的优化Adapter方案,欢迎大家交流。

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

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

优化前的log截图:

优化后的log截图:

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

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

下面附上相关代码分析:

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

Layout:

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  3. android:layout_width="fill_parent" 
  4. android:layout_height="fill_parent" 
  5. android:orientation="horizontal" > 
  6. <ImageView android:id="@+id/imageView" 
  7. android:layout_width="wrap_content" 
  8. android:layout_height="fill_parent" />" 
  9. <TextView android:id="@+id/textView" 
  10. android:layout_width="wrap_content" 
  11. android:layout_height="fill_parent" 
  12. android:layout_marginLeft="15dp" 
  13. android:gravity="center_vertical" /> 
  14. </LinearLayout> 

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

  1. public class ListViewDemo extends ListActivity{ 
  2. private final String[] mItems = new String[] { "Android""iPhone"
  3. "WindowsMobile""Blackberry""WebOS""Ubuntu""Windows7"
  4. "Max OS X""Linux""OS/2""Ubuntu""Windows7""Max OS X"
  5. "Linux""OS/2""Ubuntu""Windows7""Max OS X""Linux""OS/2"
  6. "Ubuntu""Windows7""Max OS X""Linux""OS/2""Ubuntu"
  7. "Windows7""Max OS X""Linux""OS/2""Ubuntu""Windows7"
  8. "Max OS X""Linux""OS/2""Ubuntu""Windows7""Max OS X"
  9. "Linux""OS/2""Ubuntu""Windows7""Max OS X""Linux""OS/2"
  10. "Ubuntu""Windows7""Max OS X""Linux""OS/2""Ubuntu"
  11. "Windows7""Max OS X""Linux""OS/2""Ubuntu""Windows7"
  12.  "Max OS X""Linux""OS/2""Ubuntu""Windows7""Max OS X"
  13. "Linux""OS/2""Ubuntu""Windows7""Max OS X""Linux""OS/2"
  14. "Ubuntu""Windows7""Max OS X""Linux""OS/2""Ubuntu"
  15. "Windows7""Max OS X""Linux""OS/2""Ubuntu""Windows7"
  16. "Max OS X""Linux""OS/2""Ubuntu""Windows7""Max OS X"
  17.  "Linux""OS/2""Ubuntu""Windows7""Max OS X""Linux""OS/2"
  18. "Ubuntu""Windows7""Max OS X""Linux""OS/2""Ubuntu"
  19. "Windows7""Max OS X""Linux""OS/2""Ubuntu""Windows7"
  20. "Max OS X""Linux""OS/2""Ubuntu""Windows7""Max OS X"
  21.  "Linux""OS/2""Ubuntu""Windows7""Max OS X""Linux""OS/2"
  22.  "Ubuntu""Windows7""Max OS X""Linux""OS/2""Ubuntu"
  23. "Windows7""Max OS X""Linux""OS/2""Ubuntu""Windows7"
  24. "Max OS X""Linux""OS/2""Ubuntu""Windows7""Max OS X"
  25. "Linux""OS/2""Ubuntu""Windows7""Max OS X""Linux""OS/2"
  26. "Ubuntu""Windows7""Max OS X""Linux""OS/2""Ubuntu"
  27. "Windows7""Max OS X""Linux""OS/2""Ubuntu""Windows7"
  28. "Max OS X""Linux""OS/2""Ubuntu""Windows7""Max OS X"
  29. "Linux""OS/2""Ubuntu""Windows7""Max OS X""Linux""OS/2" }; 
  30.  @Override 
  31. public void onCreate(Bundle savedInstanceState) { 
  32.     super.onCreate(savedInstanceState); 
  33.      ListViewArrayAdapter adapter = new ListViewArrayAdapter(this, mItems); 
  34.       getListView().setAdapter(adapter); 
  35.     } 

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

  1. @Override 
  2.       public View getView(int position, View convertView, ViewGroup parent) { 
  3.         long start = System.currentTimeMillis(); 
  4.         LayoutInflater inflater = (LayoutInflater) mContext.getLayoutInflater(); 
  5.         View rowView = inflater.inflate(mViewResourceId, parent, false); 
  6.         TextView textView = (TextView) rowView 
  7.                 .findViewById(mTextViewResourceId); 
  8.         ImageView imageView = (ImageView) rowView 
  9.                 .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; 

优化之后的Adapter:

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

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

责任编辑:闫佳明 来源: oschina
相关推荐

2014-12-17 09:46:30

AndroidListView最佳实践

2013-09-17 14:00:19

AndroidListView原理

2023-03-22 18:31:10

Android页面优化

2011-05-27 15:02:15

Android ListView

2022-03-29 13:27:22

Android优化APP

2011-06-03 10:48:23

Android ListView

2023-07-19 22:17:21

Android资源优化

2014-07-16 13:08:24

ListViewItem View

2022-06-07 15:33:51

Android优化实践

2013-07-10 10:21:22

Android Lis

2017-11-08 14:34:20

图片fresco程序员

2022-06-01 09:18:37

抖音ReDex算法优化

2020-03-23 15:15:57

MySQL性能优化数据库

2011-10-19 10:08:01

AndroidListView

2015-10-22 10:59:13

ListViewItem刷新

2010-01-25 17:53:35

Android Lis

2011-04-11 13:43:35

popupwindowlistviewAndroid

2014-09-17 11:20:38

AndroidListView技巧

2010-07-06 09:07:09

2023-08-25 08:06:04

项目布局LazyRow​
点赞
收藏

51CTO技术栈公众号