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

2016-02-19 10:36 30 1 收藏

给自己一点时间接受自己,爱自己,趁着下午茶的时间来学习图老师推荐的ListView的View回收引起的checkbox状态改变监听等问题解决方案,过去的都会过去,迎接崭新的开始,释放更美好的自己。

【 tulaoshi.com - 编程语言 】

之前讲到了自定义Adapter传递给ListView时,因为ListView的View回收,需要注意当ListView列表项中包含有带有状态标识控件的问题。详情可见之前发的帖[url=自定义Adapter实现ListView带多选框等状态控件的注意事项
还是这个问题,讲一个我遇到的因为两行代码位置相反引起的问题。
我的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 (checkCoutn0) {
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项数据。如果我把两行代码顺序反过来,先更改监听器,再设置状态,引发的监听器自然也就是新的监听器,逻辑也就对了。

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)

来源:http://www.tulaoshi.com/n/20160219/1595221.html

延伸阅读
标签: 女人 女性健康
女人最尴尬的9私处问题解决方案 现在的人们都追求健康,而大女人在追求健康的时候却忽略女人私处的健康保健。 女性最尴尬九个私处问题 1、阴道清洗有没有必要? 答:每天清洗外阴是有必要的,尤其是在月经期,用温开水适当清洗外阴,不让外界的病原体进入阴道,如非必要不要冲洗阴道,不需要用妇科洗液,维护女 性...
标签: Web开发
=================================== 开发java应用出现乱码是很常见的,毕竟现在unicode的使用还不是很广泛,在使用gb2312(包含了gbk简体,big5繁体)的系统中要正确实现 中文的display和数据库的存储是最基本的要求。 ============================== 1,首先developer要明确自己为什么会遇到乱码,遇到什么样的乱码...
标签: 孕期
职场孕妈咪常见问题解决方案 现在的女性都比较独立,有自己的事业,很多女性在怀孕以后,出于这样那样的原因,依然无法远离工作岗位,不愿意在家里安心地养胎。这个时候在工作过程当中要注意什么,才能够更好地保护自己和保护肚子里的宝宝呢?我们一起来关注一下吧! 如果已经由医院方面确认说怀孕的话,应该将这件...
在html编辑器中,一般默认按回车总是出现<p </p,当然按shift+enter可以是直接加<br,而很多人希望按回车就是<br换行而不是分段。 一直有人问我这个问题,而我没有写代码测试就认为在onkeydown里面判断event.keyCode==13就可以判断并解决,而后来发现似乎并没有人能用这种方法解决成功。对此表示歉意!为此,仔细研究了一下...
标签: 电脑入门
苹果电脑用bootcamp安装双系统,win7下,如果安装苹果自带的 bootcamp程序,或者bootcamp64. 则重启后将会蓝屏,报告驱动不兼容的问题。 网络上的解决思路是: 安好,重启,等待蓝屏重启。然后进入MacOSX系统,安装NTFS读取驱动paragon ntfs for mac。 然后重命名 C:/window/Systam32/driver32下的 applemtp.sys 以及 applemtn.sys 为其他...

经验教程

780

收藏

43
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部