1.从最基本的不复用开始,也就是在Adapter 的getView方法中不使用ViewHolder。
这样做,也就是在listView上下滑动,被隐藏的项滑出来的时候,每次都重绘一次这一项,这样的话会耗内存,如果item的数据量比较大的话很有可能出现滑动卡顿的现象。明显的卡顿是开发者最不愿意看到的,所以这样的使用方式,基本被pass掉了。
2.让每一项进行复用,也就是增加ViewHolder 到Adapter的getView中去。具体看代码
package com.tdotapp.rd.adapters; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; import com.tdotapp.rd.R; import java.util.List; /** * Created by GT on 2015/11/16. */ public class typeAdapter extends BaseAdapter { //上下文 private Context mContext; //item 中绑的数据 private List<String> listBeans; //构造方法 public typeAdapter(Context context, List<String> listBeans) { this.mContext = context; this.listBeans = listBeans; } @Override public int getCount() { return listBeans.size(); } @Override public Object getItem(int position) { return position; } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { //ViewHolder ViewHolder viewHolder=null; //绘制每一项的时候先判断convertView是否为空,不为空,则else里面去复用,为空,则重新赋予item布局 if (convertView == null) { //new出ViewHolder ,初始化布局文件 viewHolder = new ViewHolder(); convertView = LayoutInflater.from(mContext).inflate(R.layout.type_spinner_item, null); viewHolder.tvfabuwz = (TextView) convertView.findViewById(R.id.tvfabuwz); //调用convertView的setTag方法,将viewHolder放入进去,用于下次复用 convertView.setTag(viewHolder); } else { //复用已经存在的item的项 viewHolder = (ViewHolder) convertView.getTag(); } viewHolder.tvfabuwz.setText(listBeans.get(position)); return convertView; } class ViewHolder { TextView tvfabuwz; } }代码上增加了详细的注释,复用绝对是listView最优的优化方案,不用每次都绘制新的item项,创建一次,之后就拿来复用界面,这样一来,再多的项也不用卡耗内存了。原理相当于在上滑和下滑的时候,界面还是原来的,只是把数据换了一下。
复用有复用的好处,当然也有坏处。使用复用的时候,如果每一项里面只是展示数据,复用绝对好使,但是如果listView中的每一项都能操作(比如有个editText,输入内容,上下滑动之后,看输入框里面的内容是不是要被改变,或者在下面复用的时候出现了这个输入框里面的内容。比如,一个单选框,这一项选中之后,上下滑动之后,看这个选中状态是不是乱跑了,之前的选中状态是不是消失了。。。。。等等等,凡是与item项状态有关的,复用的时候肯定就出问题了)
怎么解决呢,这个时候你想到的肯定是不复用吧,不复用就不会出现状态改变的情况了,但是你要想清楚,不复用的话,或许滑动一会,你的这个listView就会因为不停重绘item界面而内存消耗过大,出现滑不动的情况。
下面就来说下如何避免这样的情况出现,即保证滑动之后item项修改的状态还在,又保证不会过多的重绘item使内存消耗多大。
本方法出自 xiaanming大牛的博客(稍做改动)
public class NewsAdapter extends BaseAdapter { // 定义Context private Context mContext; List<NewsListBean> list = new ArrayList<>(); //定义hashMap 用来存放之前创建的每一项item HashMap<Integer, View> lmap = new HashMap<Integer, View>(); private ImageLoader imageLoader = ImageLoader.getInstance(); public NewsAdapter(Context context, List<NewsListBean> listViewList) { this.mContext = context; this.list = listViewList; } @Override public int getCount() { return list.size(); } @Override public Object getItem(int position) { return position; } @Override public long getItemId(int position) { return 0; } @Override public View getView(final int position, View convertView, ViewGroup parent) { ViewHolder ViewHolder; //创建每一个滑动出来的item项,将创建出来的项,放入数组中,为下次复用使用 if (lmap.get(position) == null) { convertView = LayoutInflater.from(mContext).inflate(R.layout.news_item, null); ViewHolder = new ViewHolder(convertView); convertView.setTag(ViewHolder); lmap.put(position,convertView); } else { convertView = lmap.get(position); ViewHolder = (ViewHolder) convertView.getTag(); }ViewHolder.tv_newstime.setText(list.get(position).getDate()); ViewHolder.tvnewsneirong.setText(list.get(position).getContent()); ViewHolder.tvnewstitle.setText(list.get(position).getTitle()); imageLoader.displayImage(list.get(position).getImg(), ViewHolder.imgnewspic, Tools.setBeforImageoption()); return convertView; } //添加viewHolder class ViewHolder { TextView tvnewstitle,newstype,tvnewsneirong,tv_newstime; ImageView imgnewspic; public ViewHolder(View convertView) { tvnewstitle = (TextView) convertView.findViewById(R.id.tvnewtitle); imgnewspic = (ImageView) convertView.findViewById(R.id.imgnewspic); newstype= (TextView) convertView.findViewById(R.id.newstype); tvnewsneirong= (TextView) convertView.findViewById(R.id.tvnewsneirong); tv_newstime= (TextView) convertView.findViewById(R.id.tv_newstime); } }
原理就是,有新的界面了,重绘,已经存在的界面直接拿出来。这样一来,每一次的新的item项会被重新绘制界面,并将重绘的界面放入集合中做保存,可以有效的防止item项状态因服用被改变的问题出现。
但是这样的话,复用将大打折扣。内存消耗也会有所提升。
看夏大的博客回复中,有大神提到可以将状态也同时放入tag中做保存,同样在实现复用的时候复用状态。