当前位置: 移动技术网 > IT编程>移动开发>Android > ListView的View回收引起的checkbox状态改变监听等问题解决方案

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

2019年07月24日  | 移动技术网IT编程  | 我要评论

儿歌mp3打包下载,uradio,礼物包装

之前讲到了自定义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 (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项数据。如果我把两行代码顺序反过来,先更改监听器,再设置状态,引发的监听器自然也就是新的监听器,逻辑也就对了。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网