ListView是最常使用的android组件之一,关于listView的优化问题刚刚了解了一些,在这里做出总结。
PS:如果想让ListView中的item根据数据内容显示item的大小,需要在item.xml中增加下面一句话就可以了(是在整体的布局文件上加):
android:minHeight="?android:attr/listPreferredItemHeight"
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:id="@+id/item" 6 android:minHeight="?android:attr/listPreferredItemHeight" 7 android:orientation="horizontal" > 8 </LinearLayout>
优化前的自定义适配器:
1 package com.anhua.adapter; 2 3 import java.util.List; 4 import java.util.Map; 5 6 import com.anhua.bean.LocalHuoDanBean; 7 import com.example.imooc_weixinfragment.R; 8 9 import android.content.Context; 10 import android.view.LayoutInflater; 11 import android.view.View; 12 import android.view.ViewGroup; 13 import android.widget.BaseAdapter; 14 import android.widget.TextView; 15 16 public class HuoChangAadpter extends BaseAdapter { 17 private TextView title;// 承运号 18 private TextView number;// 缺货件数 19 private TextView no;//序号 20 private List<Map<String, Object>> arrayList; 21 private Context context;// 运行上下文 22 private int item; 23 private LayoutInflater inflater; 24 public HuoChangAadpter(List<Map<String, Object>> arrayList, int item, 25 Context context) { 26 this.arrayList = arrayList; 27 this.context = context; 28 this.item = item; 29 this.inflater = LayoutInflater.from(context);// 创建视图容器并设置上下文 30 } 31 @Override 32 public int getCount() { 33 // TODO Auto-generated method stub 34 return arrayList.size(); 35 } 36 37 @Override 38 public Object getItem(int position) { 39 // TODO Auto-generated method stub 40 return arrayList.get(position); 41 } 42 43 @Override 44 public long getItemId(int position) { 45 // TODO Auto-generated method stub 46 return 0; 47 } 48 49 @Override 50 public View getView(int position, View convertView, ViewGroup parent) { 51 if (convertView == null) { 52 convertView = inflater.inflate(item, null); 53 title = (TextView) convertView.findViewById(R.id.chengyun); 54 number = (TextView) convertView.findViewById(R.id.number); 55 no=(TextView) convertView.findViewById(R.id.no); 56 } 57 String titles = arrayList.get(position).get("ID").toString();// 承运号 58 String numbers = arrayList.get(position).get("quantity").toString();// 缺货件数 59 String nos=(position+1)+""; 60 no.setText(nos); 61 title.setText(titles); 62 number.setText(numbers); 63 return convertView; 64 } 65 }
我之前一直是使用上面的代码来写自定义适配器的,但是这种方式仅仅限于一些简单的Item组件。最近遇到了给listView的数据增加序号排序的问题,使用优化前的代码直接造成序号的书序错乱,而使用下面的优化后的代码序号排序错乱问题就解决了。
优化后的自定义适配器:
1 package com.anhua.adapter; 2 3 import java.util.List; 4 import java.util.Map; 5 6 import com.anhua.bean.LocalHuoDanBean; 7 import com.example.imooc_weixinfragment.R; 8 9 import android.content.Context; 10 import android.view.LayoutInflater; 11 import android.view.View; 12 import android.view.ViewGroup; 13 import android.widget.BaseAdapter; 14 import android.widget.TextView; 15 16 public class HuoChangAadpter extends BaseAdapter { 17 18 private List<Map<String, Object>> arrayList; 19 private Context context;// 运行上下文 20 private int item; 21 private LayoutInflater inflater; 22 23 public HuoChangAadpter(List<Map<String, Object>> arrayList, int item, 24 Context context) { 25 this.arrayList = arrayList; 26 this.context = context; 27 this.item = item; 28 this.inflater = LayoutInflater.from(context);// 创建视图容器并设置上下文 29 } 30 31 @Override 32 public int getCount() { 33 // TODO Auto-generated method stub 34 return arrayList.size(); 35 } 36 37 @Override 38 public Object getItem(int position) { 39 // TODO Auto-generated method stub 40 return arrayList.get(position); 41 } 42 43 @Override 44 public long getItemId(int position) { 45 // TODO Auto-generated method stub 46 return 0; 47 } 48 49 @Override 50 public View getView(int position, View convertView, ViewGroup parent) { 51 ViewHolder holder = null; 52 if (convertView == null) { 53 convertView = inflater.inflate(item, null); 54 holder = new ViewHolder(); 55 56 holder.title = (TextView) convertView.findViewById(R.id.chengyun); 57 holder.number = (TextView) convertView.findViewById(R.id.number); 58 holder.no = (TextView) convertView.findViewById(R.id.no); 59 convertView.setTag(holder); 60 } else { 61 // viewHolder被复用 62 holder = (ViewHolder) convertView.getTag(); 63 } 64 String titles = arrayList.get(position).get("ID").toString();// 承运号 65 String numbers = arrayList.get(position).get("quantity").toString();// 缺货件数 66 String nos = (position + 1) + ""; 67 holder.no.setText(nos); 68 holder.title.setText(titles); 69 holder.number.setText(numbers); 70 return convertView; 71 } 72 73 private class ViewHolder { 74 private TextView title;// 承运号 75 private TextView number;// 缺货件数 76 private TextView no;// 序号 77 } 78 }
其实对于listView的优化方案可以从以下角度来考虑:
- 1.在adapter中的getView方法中尽量少使用逻辑
- 2.尽最大可能避免GC
- 3.滑动的时候不加载图片
- 4.将ListView的scrollingCache和animateCache设置为false
- 5.item的布局层级越烧越好
- 6.使用ViewHolder
1.在adapter中的getView方法中尽量少使用逻辑
不要在你的getView()中写过多的逻辑代码,我们可以将这些代码放在别的地方,例如:
优化前的getView():
1 @Override 2 public View getView(int position, View convertView, ViewGroup paramViewGroup) { 3 Object current_event = mObjects.get(position); 4 ViewHolder holder = null; 5 if (convertView == null) { 6 holder = new ViewHolder(); 7 convertView = inflater.inflate(R.layout.row_event, null); 8 holder.ThreeDimension = (ImageView) convertView.findViewById(R.id.ThreeDim); 9 holder.EventPoster = (ImageView) convertView.findViewById(R.id.EventPoster); 10 convertView.setTag(holder); 11 12 } else { 13 holder = (ViewHolder) convertView.getTag(); 14 } 15 16 //在这里进行逻辑判断,这是有问题的 17 if (doesSomeComplexChecking()) { 18 holder.ThreeDimention.setVisibility(View.VISIBLE); 19 } else { 20 holder.ThreeDimention.setVisibility(View.GONE); 21 } 22 23 // 这是设置image的参数,每次getView方法执行时都会执行这段代码,这显然是有问题的 24 RelativeLayout.LayoutParams imageParams = new RelativeLayout.LayoutParams(measuredwidth, rowHeight); 25 holder.EventPoster.setLayoutParams(imageParams); 26 27 return convertView; 28 }
优化后的getView():
1 @Override 2 public View getView(int position, View convertView, ViewGroup paramViewGroup) { 3 Object object = mObjects.get(position); 4 ViewHolder holder = null; 5 6 if (convertView == null) { 7 holder = new ViewHolder(); 8 convertView = inflater.inflate(R.layout.row_event, null); 9 holder.ThreeDimension = (ImageView) convertView.findViewById(R.id.ThreeDim); 10 holder.EventPoster = (ImageView) convertView.findViewById(R.id.EventPoster); 11 //设置参数提到这里,只有第一次的时候会执行,之后会复用 12 RelativeLayout.LayoutParams imageParams = new RelativeLayout.LayoutParams(measuredwidth, rowHeight); 13 holder.EventPoster.setLayoutParams(imageParams); 14 convertView.setTag(holder); 15 } else { 16 holder = (ViewHolder) convertView.getTag(); 17 } 18 19 // 我们直接通过对象的getter方法代替刚才那些逻辑判断,那些逻辑判断放到别的地方去执行了 20 holder.ThreeDimension.setVisibility(object.getVisibility()); 21 22 return convertView; 23 }
2.GC 垃圾回收器
当你创建了大量的对象的时候,GC就会频繁的执行,所以在getView()方法中不要创建很多的对象,最好的优化是,不要在ViewHolder以外创建任何对象,如果你的你的log里面发现“GC has freed some memory”频繁出现的话,那你的程序肯定有问题了。你可以检查一下:
a) item布局的层级是否太深
b) getView()方法中是否有大量对象存在
c) ListView的布局属性
3.加载图片
如果你的ListView中需要显示从网络上下载的图片的话,我们不要在ListView滑动的时候加载图片,那样会使ListView变得卡顿,所以我们需要再监听器里面监听ListView的状态,如果滑动的时候,停止加载图片,如果没有滑动,则开始加载图片
1 listView.setOnScrollListener(new OnScrollListener() { 2 3 @Override 4 public void onScrollStateChanged(AbsListView listView, int scrollState) { 5 //停止加载图片 6 if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_FLING) { 7 imageLoader.stopProcessingQueue(); 8 } else { 9 //开始加载图片 10 imageLoader.startProcessingQueue(); 11 } 12 } 13 14 @Override 15 public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { 16 // TODO Auto-generated method stub 17 18 } 19 });
4.将ListView的scrollingCache和animateCache设置为false
scrollingCache: scrollingCache本质上是drawing cache,你可以让一个View将他自己的drawing保存在cache中(保存为一个bitmap),这样下次再显示View的时候就不用重画了,而是从cache中取出。默认情况下drawing cahce是禁用的,因为它太耗内存了,但是它确实比重画来的更加平滑。而在ListView中,scrollingCache是默认开启的,我们可以手动将它关闭。
animateCache: ListView默认开启了animateCache,这会消耗大量的内存,因此会频繁调用GC,我们可以手动将它关闭掉
优化前的ListView
1 <ListView 2 android:id="@android:id/list" 3 android:layout_width="match_parent" 4 android:layout_height="wrap_content" 5 android:cacheColorHint="#00000000" 6 android:divider="@color/list_background_color" 7 android:dividerHeight="0dp" 8 android:listSelector="#00000000" 9 android:smoothScrollbar="true" 10 android:visibility="gone" />
优化后的ListView
1 <ListView 2 android:id="@android:id/list" 3 android:layout_width="match_parent" 4 android:layout_height="wrap_content" 5 android:divider="@color/list_background_color" 6 android:dividerHeight="0dp" 7 android:listSelector="#00000000" 8 android:scrollingCache="false" 9 android:animationCache="false" 10 android:smoothScrollbar="true" 11 android:visibility="gone" />
5.减少item的布局的深度
我们应该尽量减少item布局深度,因为当滑动ListView的时候,这回直接导致测量与绘制,因此会浪费大量的时间,所以我们应该将一些不必要的布局嵌套关系去掉。减少item布局深度
6.使用ViewHolder
这个大家应该非常熟悉了,但是不要小看这个ViewHolder,它可以大大提高我们ListView的性能
ListView的优化我们已经讲完了,如果在你的项目中,这些基本优化你还没有做到的话,那么你的ListView是有问题的,还有很大的提升潜力,以后再使用ListView的时候,一定要将这几点考虑进去,发挥它的最大的性能。
参考文章:http://blog.csdn.net/nugongahou110/article/details/47128125