ListView的View回收引起的checkbox状态改变监听等问题解决方案

我的ListView中每行View包含一个ImageView、TextView、CheckBox。当ListView中有一个或一个一行CheckBox被选中就让ListView上面的Button显示,否则就隐藏。因此,需要对每行View中的CheckBox设置监听。我使用CheckBox中的OnCheckedChangeListener监听器,当CheckBox的状态发生改变的时候就会触发这个监听器。先看下我自定义给ListView的Adapter的getView方法中的一些关键代码:
这是getView方法中使用到的内部类:

复制代码 代码如下:
static class ViewHolder { public ImageView imageView; public TextView textView; public CheckBox checkBox;
}

这是getView方法中利用ListView回收机制循环利用View的代码:

复制代码 代码如下:
public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder; if (convertView == null) { convertView = inflater.inflate(R.layout.searchitem, null);
viewHolder = new ViewHolder(); viewHolder.imageView = (ImageView) convertView .findViewById(R.id.searchitemimage); viewHolder.textView = (TextView) convertView .findViewById(R.id.searchitemtext);
viewHolder.checkBox = (CheckBox) convertView
.findViewById(R.id.searchitemcheckbox); convertView.setTag(viewHolder);
} else { // Log.i(CodeUtils.SEARCHTAG, "view is reuse"); viewHolder = (ViewHolder) convertView.getTag(); }

接下来是对其中checkbox设置显示状态和监听器的代码:

复制代码 代码如下:
viewHolder.checkBox
.setOnCheckedChangeListener(new SearchItemOnCheckedChangeListener(
position, state)); viewHolder.checkBox.setChecked(state[position]);

之前说过了,因为ListView的回收,需要使用一个数组或list来记录每项数据中checkbox的状态。这里,state是与ListView列表等长的boolean数组,用于记录每个position(也就是每个列表项数据的id)标识的数据上checkbox应该显示的状态,初始的状态都是false。构造checkbox监听器的时候需要传递当前View的position,以及整个列表checkbox的状态数组state。以下是checkBox状态改变监听器的代码:

复制代码 代码如下:
public class SearchItemOnCheckedChangeListener implements OnCheckedChangeListener {
private int id; private Boolean[] state; public SearchItemOnCheckedChangeListener(int id, Boolean[] state) { this.id = id;
this.state = state; } @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
state[id] = isChecked; if (isChecked) { checkedCount++; }else{
checkedCount--; } if (checkCoutn>0) {
searchButton.setVisibility(Button.INVISIBLE); } else {
searchButton.setVisibility(Button.VISIBLE); } } } }

这里面checkedCount初始值为0的整型,用于记录被选中多选框的数量。searchButton是根据checkbox而决定显示还是隐藏的按钮。
以上整个逻辑功能的实现代码。开头说了,这是一个我因为ListView的回收机制和两行代码位置相反引起的问题。两行代码的位置相反将导致完全不同的结果,所指的就是设置checkbox监听器和状态的两行代码,起初我的顺序为:

复制代码 代码如下:
viewHolder.checkBox.setChecked(state[position]);
viewHolder.checkBox.setOnCheckedChangeListener(new SearchItemOnCheckedChangeListener(position, state));

这样的顺序出现的问题是,当我拉动列表后,因为拉动被隐藏的列表项状态将被更改为false。这很不可思议,因为我已经分离了一个状态数组来记录每个checkbox的状态,想来想去只有一个可能,就是状态数组中的值改变了,而改变状态数组的值位置就在于OnCheckedChangeListener中。Debug了几个小时,才想通了问题就在于这两行代码为位置顺序。
起因还是得讲到ListView的回收机制。假如我的ListView最多只能显示10个View,那么起初就会调用十次getView构造十个全新的View(包括对其中的checkbox设置监听器)。当我将列表往下拉出现第11个列表项的时候,顶部第一个列表项被隐藏,同样会再调用一次getView,不过此时getView的参数将返回刚刚被隐藏的第一个列表项的View,并对这个View更改数据作为即将出现的第11个View。问题就出在这里,我把checkbox.setChecked()方法调用放在了设置监听器前面,此时因为更改了checkbox的状态,势必引起触发状态更改的监听器。注意!由于第11个View是用被隐藏的第1个View回收来的,虽然还没有执行下一行设置监听器的代码,但实际上它已经拥有了一个状态监听器,这个监听器是这个View还是作为第一个View时设置。那个时候的监听器设置更改的第一项的数据,而不是第11项数据。因此,理所当然不能正确更改第11项数据,反而更改了无辜的第1项数据。如果我把两行代码顺序反过来,先更改监听器,再设置状态,引发的监听器自然也就是新的监听器,逻辑也就对了。

转载于:https://www.cnblogs.com/dasb/p/4656196.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值