今天用recyclerview时候发现checkbox重复使用会导致OnCheckedChangeListener 出现一个不太友好的问题,问题是这样的:
Recyclerview 会回收使用组件,回收checkbox的时候会触发OnCheckedChangeListener 事件,导致我们写的listener中的逻辑会被打乱
比如我选中了一个checkbox,那么当view滚动导致这个checkbox 滑动出可视范围的时候 ,OnCheckedChangeListener事件会被触发,这样相当于自动把我选中的取消了。
为了解决这个为题巨硬了一下,发现stackoverflow上面也没找到特别合适的方法,最后自己搞了一个办法,还是比较简洁的,直接上代码:
public ViewHolder(View itemView) {
super(itemView);
root = itemView;
cb = new CheckBox(root.getContext());
cb.setTag(new Integer(-2));//这里
((LinearLayout)root).addView(cb);
}
初始化控件的时候给他打一个tag,设置一个值,表示这个组件不显示的时候应该表示的状态
2.
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
CheckBox cb = ((ViewHolder) holder).getCheckBox();
// System.out.println("set text");
cb.setText(displayedData.getDisplayName(position));
cb.setChecked(displayedData.isChosen(position));
cb.setTag(new Integer(position));//把组件的状态更新为一个合法的状态值
cb.setOnCheckedChangeListener(this.listener);
}
bind的时候把这个tag设置一个合法的值,我这里因为listener事件处理的时候要用到position,所以我直接设置成position了
3.
private CompoundButton.OnCheckedChangeListener listener =
new CompoundButton.OnCheckedChangeListener(){
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
//System.out.println(isChecked);
//System.out.println(buttonView.getTag());
int index = (int)buttonView.getTag();//事件处理前要判断状态
if (index == -2) return;
if(isChecked){
displayedData.addToTasks(index);
}else{
displayedData.removeFromTasks(index);
}
}
};
然后是listener这里,进行逻辑处理之前判断一下状态,如果是非法状态就不执行我们的逻辑了
4.
@Override
public void onViewRecycled(RecyclerView.ViewHolder holder) {
CheckBox cb = ((ViewHolder) holder).getCheckBox();
cb.setTag(new Integer(-2));
super.onViewRecycled(holder);
}
这段应该是最重要的了,onViewRecycled这个方法会在这个组件脱离可视范围,进入android自己的回收缓存时候调用,那么我们这个时候要把tag改成非法值,告诉listener这个时候不要执行我们的逻辑了
另外还有一个onFailedToRecycleView方法,不过既然这个组件没被回收,那么也不会出现问题咯,所以就不用管了
主要思路就是给组件一个in user or not 的标志,基本这样就解决了。