ListView + CheckBox(或者是RadioGroup等控件)的混乱选中原理

来源:互联网 发布:南京大学网络教育2017 编辑:程序博客网 时间:2024/05/21 08:54

1,常用的写法,只展示Adapter,问题原因就在Adapter中

    class Adapter1 extends BaseAdapter{        @Override        public int getCount() {            return list.size();        }        @Override        public Object getItem(int position) {            return null;        }        @Override        public long getItemId(int position) {            return 0;        }        @Override        public View getView(int position, View convertView, ViewGroup parent) {            final int index = position;            ViewHolder viewHolder;            if(convertView == null){                viewHolder = new ViewHolder();                convertView = LayoutInflater.from(ListViewCheckBox.this).inflate(R.layout.listview_checkbox_item, null);                viewHolder.layout = (LinearLayout)convertView.findViewById(R.id.layout);                viewHolder.textView = (TextView)convertView.findViewById(R.id.textView);                viewHolder.checkBox = (CheckBox)convertView.findViewById(R.id.checkBox);                convertView.setTag(viewHolder);            }else{                viewHolder = (ViewHolder)convertView.getTag();            }            viewHolder.textView.setText(list.get(position).name);            if(list.get(position).type == A.TYPE_CHECKED){                viewHolder.checkBox.setChecked(true);            }else{                viewHolder.checkBox.setChecked(false);            }            /*点击checkBox所在行改变checkBox状态*/            /*final ViewHolder vv = viewHolder;            viewHolder.layout.setOnClickListener(new OnClickListener() {                @Override                public void onClick(View v) {                    if(vv.checkBox.isChecked()){                        vv.checkBox.setChecked(false);                        list.get(index).type = TYPE_CHECKED;                    }else{                        vv.checkBox.setChecked(true);                        list.get(index).type = TYPE_NOCHECKED;                    }                }            });*/            viewHolder.checkBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {                @Override                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {                    if(isChecked){                        list.get(index).type = A.TYPE_CHECKED;                    }else{                        list.get(index).type = A.TYPE_NOCHECKED;                    }                }            });            return convertView;        }    }    class ViewHolder{        LinearLayout layout;        TextView textView;        CheckBox checkBox;    }    class A {        public static final int TYPE_CHECKED = 1;        public static final int TYPE_NOCHECKED = 0;        String name;        int type;        public A(String name,int type){            this.name = name;            this.type = type;        }    }}

这时出现了混乱选中问题,为什么呢?

首先,我们使用了一个数组来存储每个CheckBox的状态,如果被选中,我们在setOnCheckedChangeListener 监听事件中的OnCheckChanged()方法中将状态修改为被选中,如果被取消选中,则改为被取消选中。

我们还使用了Convertview + ViewHolder来进行view的复用,提高listView的加载效率以及减少每次new一个View 的开销。这也是导致我们出现了混乱选中的根源所在。

下面来分析下到底是如何出现的混乱选中。

1,假设我们的convertview有着10个复用的View对象(这个好像会跟显示View时,一个屏幕能放下多少View相关,如果最多只能显示五个,那么只使用5个用来复用的View),那么当我们分别用完了这十个之后就会开始复用,比如说我的界面中有30个用ListView+CheckBox组成的选择题。

我们从其他地方点进ListView所在的Activity,ListView进行加载,那么前10个是没有问题的。假设第一个我们进行了选择,状态为Checked。当我们下滑,显示到第11个的时候,这个时候第11个viewItem会复用第一个item的View。

这时。当将这一个viewItem加载到ListView的第11个位置时,它的状态是Checked。通过从状态数组中读取第11个Item的选中状态时,发现我并没有选中第11个Item,这时就会将第11个Item设置为未选中。

一切看起来这么顺利!!!

但是!

当我们的第11个Item从复用的第一个ItemView的选中状态 到 从状态数组中读取的未选中状态,是经过了一次setOnCheckedChangeListener 选中变化事件的监听的。

而且!!

我们仔细看,我们的setOnCheckedChangeListener 监听事件的设置是写在了我们初始化item的选中状态之后的。

也就是说!!

这时候我们的setOnCheckedChangeListener 监听事件是在第一个ViewItem初始化时设置的那个监听事件。

这个时候,由于发生了选中状态的变化,由第一个Item的选中变化监听事件所监听到了,从而改变了第一个Item的状态。当滑动几次时,由于反复的在复用convertView,便出现了非常令人头疼的混乱选中。。!

解决办法:把添加监听器的方法加到初始化view中checkBox状态的代码之前即可
。这时监听器便不会混乱监听了。

完美~~~

class Adapter1 extends BaseAdapter{        @Override        public int getCount() {            return list.size();        }        @Override        public Object getItem(int position) {            return null;        }        @Override        public long getItemId(int position) {            return 0;        }        @Override        public View getView(int position, View convertView, ViewGroup parent) {            final int index = position;            ViewHolder viewHolder;            if(convertView == null){                viewHolder = new ViewHolder();                convertView = LayoutInflater.from(ListViewCheckBox.this).inflate(R.layout.listview_checkbox_item, null);                viewHolder.layout = (LinearLayout)convertView.findViewById(R.id.layout);                viewHolder.textView = (TextView)convertView.findViewById(R.id.textView);                viewHolder.checkBox = (CheckBox)convertView.findViewById(R.id.checkBox);                convertView.setTag(viewHolder);            }else{                viewHolder = (ViewHolder)convertView.getTag();            }            viewHolder.checkBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {                @Override                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {                    if(isChecked){                        list.get(index).type = A.TYPE_CHECKED;                    }else{                        list.get(index).type = A.TYPE_NOCHECKED;                    }                }            });            viewHolder.textView.setText(list.get(position).name);            if(list.get(position).type == A.TYPE_CHECKED){                viewHolder.checkBox.setChecked(true);            }else{                viewHolder.checkBox.setChecked(false);            }            return convertView;        }    }
阅读全文
1 0
原创粉丝点击