ListView中复用机制产生的数据错乱的一些思考

前几天,遇到了一个小问题,就是listview文件列表中的全选上传的时候,发现并不是全选了。很疑惑,自认为对listview的原理,探究以及adapter的自定义编写有些许了解了,最后明白了,在listview还有一个Recycler缓存机制,就是说在setAdapter后,getView方法返回的是可见的视图item,其他的item只有滚动到屏幕中来后才会执行getView的方法。这也就是为什么我的文件全选没有选到的原因了,就是我把全选写到getView中了。。。所以GG了

这里写图片描述

那么要怎么实现全选,反选呢,其实很简单,定义一个Boolean类型的数组,这是我们常规会想到的了,每一次的全选反选或者对checkbox操作就对相应位置的数组进行更改boolean值就可以了。但是这么搞确实有点麻烦啊,索性就在Bean里面做点文章,增加一个boolean的字段来标记。

看下ProductBean.java代码

package com.nst.Bean;

/**
 * Created by zsj on 2016/7/21.
 */
public class ProductBean {

    private int productId;
    private String title;
    private boolean chk;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public boolean isChk() {
        return chk;
    }

    public void setChk(boolean chk) {
        this.chk = chk;
    }


    public int getProductId() {
        return productId;
    }

    public void setProductId(int productId) {
        this.productId = productId;
    }
}
Adapter中的代码

package com.nst.adapter;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.TextView;

import com.nst.Bean.ProductBean;
import com.nst.com.hellowworld.R;

import java.util.List;

/**
 * Created by zsj on 2016/7/21.
 */
public class ProductAdapter extends BaseAdapter {


    private int mResource;
    private Context mContext;
    private List<ProductBean> mData;


    //构造方法
    public  ProductAdapter(int LayoutId, Context mContext, List<ProductBean> mData) {
        this.mContext = mContext;
        this.mResource = LayoutId;
        this.mData = mData;
    }

    @Override
    public int getCount() {
        return mData.size();
    }

    @Override
    public Object getItem(int position) {
        return mData.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    //是否可见
    boolean isVisible = false;
    public void setVisible(Boolean visible) {
        isVisible = visible;
        notifyDataSetChanged();

    }
    @Override
    public View getView(final int position, View contentview, ViewGroup viewGroup) {
        ViewHolder viewHolder = null;
        if (contentview == null) {
            viewHolder = new ViewHolder();
            //动态加载布局
            contentview = LayoutInflater.from(mContext).inflate(mResource, null);
            viewHolder.tvTitle = (TextView) contentview.findViewById(R.id.tv_title);
            viewHolder.chkMybox = (CheckBox) contentview.findViewById(R.id.chk_box);
            contentview.setTag(viewHolder);

        } else {
            viewHolder = (ViewHolder) contentview.getTag();
        }
        viewHolder.tvTitle.setText(mData.get(position).getTitle());
        viewHolder.chkMybox.setChecked(mData.get(position).isChk());
        viewHolder.chkMybox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
                mData.get(position).setChk(b);//更改List<bean>中的数据
            }
        });

        if(isVisible){
           viewHolder.chkMybox.setVisibility(View.VISIBLE);
        }else{
            viewHolder.chkMybox.setVisibility(View.GONE);
        }

        return contentview;
    }

    //容器
    public class ViewHolder {
        TextView tvTitle;
        CheckBox chkMybox;

    }
}
MainActivity中的代码:

package com.nst.com.hellowworld;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.ListView;
import android.widget.TextView;

import com.nst.Bean.ProductBean;
import com.nst.adapter.ProductAdapter;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class MainActivity extends Activity implements View.OnClickListener {

    private TextView tvOperate;
    private ListView lvProduct;
    private int[] subCount;
    private List<String> data;
    private ProductAdapter mAdapter;
    private List<ProductBean> ListBean;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initData();
        initListener();
    }

    private void initListener() {


    }

    private void initData() {
        //获取系统时间
        Date date = new Date();
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time = dateFormat.format(date);
        data = new ArrayList<String>();
        ListBean = new ArrayList<ProductBean>();
        for (int i = 0; i < 20; i++) {
            ProductBean bean = new ProductBean();
            bean.setChk(false);
            bean.setProductId(i);
            bean.setTitle(i + "、" + time);
            ListBean.add(bean);
        }
        mAdapter = new ProductAdapter(R.layout.product_items, MainActivity.this, ListBean);
        lvProduct.setAdapter(mAdapter);

    }

    //全选或者全不选
    public void selectAll(Boolean b) {
        //遍历算法,相当于for循环
        for (ProductBean bean : ListBean) {
            bean.setChk(b);
        }
        mAdapter.notifyDataSetChanged();
    }

    //反选
    public void selectopp() {
        for (ProductBean bean : ListBean) {
            bean.setChk(!bean.isChk());
        }
        mAdapter.notifyDataSetChanged();
    }

    private void initView() {
        tvOperate = (TextView) findViewById(R.id.tv_op);
        lvProduct = (ListView) findViewById(R.id.product_all);
        tvOperate.setOnClickListener(this);

    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.tv_op:
                //显示checkbox
                if (tvOperate.getText().equals("操作")) {
                    tvOperate.setText("全选");
                    mAdapter.setVisible(true);
                } else if (tvOperate.getText().equals("全选")) {
                    tvOperate.setText("反选");
                    selectAll(true);
                } else if (tvOperate.getText().equals("反选")) {
                    tvOperate.setText("隐藏");
                    selectopp();
                } else if (tvOperate.getText().equals("隐藏")) {
                    tvOperate.setText("操作");
                    selectAll(false);//全不选
                    mAdapter.setVisible(false);
                }
                break;
        }
    }
}

xml文件就不贴出来了。。。就是个listview,然后那个item的布局文件也不贴了。。。最后效果图附上:
这里写图片描述

写这个小例子主要也是为了理解,主要是getView的方法返回的是我们屏幕中所看得见的item,返回的是view,然后第一次加载的时候,只会初始化能看见的8个item,可以打断点看到。。。你往下拖后,才继续执行第9个。。。以及后面的,这就是listview自带的缓存机制了,偷张图片给你们理解下:

这里写图片描述

demo下载地址。。。我觉得不需要啊,好虚啊,这么简单的demo,然后,我们也可以去了解下更强大的recyclerview。。。下次再来

总结下:好好码代码,哪怕是最简单的代码~
这里由这个demo的理解总结出一种算法:取出N个集合中的交集,首先将每个集合添加到一个新的集合中,将所有的标识设置为1,即首先设定每个集合中的元素重复了一次,依次遍历其他集合中的元素对大集合中的元素进行比对,更改那个1,即重复的次数,就可以算出所有集合中所有元素重复的次数。
这里写图片描述
番外篇:今天是个好日子,解决了一个一直困扰我的一个问题。就是在listview的复用布局的过程中,item中进行多选、单选、动画播放开关等操作的过程中会产生数据错乱的问题。这个问题产生的原因主要是listview的布局复用机制,一次只会生成一个屏幕的item数量,然后进行复用。其实解决的方案很简单,就是将布局和model关联起来,将这个状态值存到作为一个字段添加到model中。。。每次操作改变modle中的字段的状态。或者说,你有时候为了快速便捷用到了pojo直接转json,而服务端并不需要这个字段的话。那么我们可以专门为它建立一个实体类model记录每个条目的状态。然后每次滚动到对应的item的时候,都会执行getview的方法,再将model中对应的值赋值给它。那么你的item中假设有多选框,音乐播放列表动画,单选框的时候,点击那个时间,改变model中的值,我想这也是MVC的思想吧。把Model和View分离开来,真的很奇妙~have a nice day

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值