android app -- 关于listview的几种用法(复用,不复用,半复用)解决item状态改变的问题

来源:互联网 发布:淘宝网交电费 编辑:程序博客网 时间:2024/06/06 05:47


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;}//添加viewHolderclass 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中做保存,同样在实现复用的时候复用状态。


如有不明确的地方,可以回复,荣幸与各位开发者公共探讨。


原创文章,转载请注明出处:
http://blog.csdn.net/qq_33078541?viewmode=contents

6 0
原创粉丝点击