在listView适配器的内存优化给点击事件带来的麻烦

最近做了一个listview,想在点击Item的时候让这个Item的图标改变,监听器在适配器里面做,结果跑起来发现,点击之后,改变图标的竟然不是所点击的Item,而是屏幕中最后一个Item(注意!不是最后一个Item,而是屏幕中已经显示的Item的最后一个)
先贴一段适配器代码

public class DetailAdapter extends BaseAdapter {
    private List<FoodDetail> foodDetail;
    private LayoutInflater layoutInflater;//加载布局的准备工作
    private Context context;
    private int local;
    private int [] image;
    ViewHolder holder;
    public DetailAdapter(List<FoodDetail> foodDetail,Context context,int[] image) {
        this.foodDetail = foodDetail;
        this.context=context;
        layoutInflater = LayoutInflater.from(context);
        this.image = image;
    }

    @Override
    public int getCount() {
        // TODO Auto-generated method stub
        return foodDetail.size();
    }

    @Override
    public Object getItem(int position) {
        // TODO Auto-generated method stub
        return foodDetail.get(position);
    }

    @Override
    public long getItemId(int position) {
        // TODO Auto-generated method stub
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // TODO Auto-generated method stub
        local = position;
        if (convertView == null) {
            holder = new ViewHolder();
            convertView = layoutInflater.inflate(R.layout.listview_detail, null);
            holder.relativeLayout = (RelativeLayout) convertView.findViewById(R.id.one);
            holder.imageView = (ImageView) 
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        holder.imageView.setBackgroundResource(image[position]);
holder.imageView.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                //注意设置imageview背景这段话
                holder.imageView.setBackground(background);
            }
        });
        return convertView;
    }
    public static class ViewHolder {
        public ImageView imageView;
    }
}

如上面代码,在onClick()方法里修改Imageview的背景,实际上所修改的不是你当前所点击的Item,而是屏幕中所显示的最后一条Item的Imageview!
注意!!!!!不是最后一个Item,而是屏幕中所显示的最后一个Item。这一切都是listview在内存优化方面做的太好的“错”!
下面顺便说下lisview的内存机制
先看一张图片:这里写图片描述
注意里面test数值的变化(不要看a),test变量是我在getView()方法里定义的一个final的int常量,final int test = (int) ( 50 * Math.random() + 50);
值为50-100的随机数,点击listview的任意一个Item,就会打印log日志!通过我的多次实验,发现如果不滑动listview,只是一直点击某一个Item的时候,test的数值是不会改变的!然而,当你滑动listview之后,再次点击这个Item,就会发现test的值已经改变!
这也验证了listview的加载过程不是一下子全部加载,而是至加载一部分,滑动之前的test在滑动的时候,会被内存多次收回和重新建立,当再次回到你滑动之前的Item的时候,这个常量已经不再是当年的那个常量了;
上个图:
这里写图片描述
下面解释一下:
1、如果你有几千几万甚至更多的选项(item)时,其中只有可见的项目(满屏显示的Item数目)存在内存(说的优化就是说在内存中的优化!)中,其他的在Recycler中

2、ListView先请求一个type1视图(getView)然后请求其他可见的项目。convertView在getView中是空(null)的,第一次都是为空的,只要显示过了convertView都不为空,会保存在Recycler中

3、当item1滚出屏幕,并且一个新的项目从屏幕低端上来时,ListView再请求一个type1视图。convertView此时不是空值了,它的值是item1。你只需设定新的数据然后返回convertView,不必重新创建一个视图,省去了inflate和findViewById的时间,性能就得到了优化。
接着说上面的问题:当你older.imageView.setBackground(background);的时候,实际上,这个控件已经不是你点击的那个Item的了。而是指向屏幕中显示的最后一个Item。所以才造成了无论我点击屏幕中的任何Item,都只是最后一个Item在改变

解决的方法就是使用监听事件里的参数去获取你想要改变的布局,就是那个View v参数,

public void onClick(View v) {

                holder.imageView.setBackground(background);
            }

使用这个v.getparent()一层层获取到你想要的东西,最后要记住强制转换,因为你获取到的是view控件,也许没有你想要的方法。
或者,简单粗暴:

holder.ImageButton.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    //通过v获取当前你的所点击的Item
                    ImageButton imageButton = (ImageButton) v;
                    imageButton.setBackgroundResource(R.drawable.started);
                    } 
            });

这样,天下太平,你点击哪个Item,哪个Item的图标就改变!!
最后,希望大家多多指教,欢迎补充更好的方法!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值