遇到了这个问题,记录下,方便以后查看,也让道友们看看
先上整体代码
public class MainActivity extends AppCompatActivity {
private ListView listView;
private List<Entity> list;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.listView);
initData();
listView.setAdapter(new MyAdapter(this,list));
}
private void initData() {
list = new ArrayList<>();
for (int i = 0; i < 20; i++){
Entity entity = new Entity();
entity.isChecked = false;
entity.text = "这是第"+i+"条数据";
list.add(entity);
}
}
private class MyAdapter extends BaseAdapter{
private Context context;
private List<Entity> list;
MyAdapter(Context context,List<Entity> list){
this.context = context;
this.list = list;
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position,View convertView,ViewGroup,parent){
ViewHolder holder;
if (convertView == null){
convertView = LayoutInflater.from(context)
.inflate(R.layout.list_item,parent,false);
holder = new ViewHolder(convertView);
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
}
final Entity data = list.get(position);
holder.checkBox.setChecked(data.isChecked);
holder.text.setText(data.text);
holder.checkBox.setOnCheckedChangeListener(
new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
data.isChecked = isChecked;
}
});
return convertView;
}
class ViewHolder{
TextView text;
CheckBox checkBox;
public ViewHolder(View convertView){
text = (TextView) convertView.findViewById(R.id.title);
checkBox = (CheckBox) convertView
.findViewById(R.id.checkbox);
}
}
}
}
整体布局很简单,LinearLayout中放个ListView
ListView中的Item布局就是在LinearLayout中放了个TextView和一个CheckBox
如果不是用ViewHolder的话,是没问题的(可以自己试下),
上面通过ViewHolder来优化,出现选择混乱问题。
解决办法:
将holder.checkBox.setChecked(data.isChecked);
语句放在CheckBox选择改变监听事件后面,即可解决
原因分析
我们通过ViewHolder重用convertView,这时对于第一个条目,
我们选中后,滑动ListView,下面出来的item会重用第一个消息item的布局
再看我们的代码,每次根据list中对应position初始化checkbox状态,
看着好像也没问题,但是事实出现了问题...
一直以为是重用convertView的时候系统会给我们重置一些状态,后来发现不是...
我们勾选第一个item的 checkbox,然后滑动ListView到第一个条目消失,
这时最下面的item是重用第一个item的布局的,
这时我们初始化布局信息或状态,但是在初始化CheckBox状态时,使用的数据
为list中对应position的数据,此时监听事件还未重置,
监听事件改变的数据依旧是list中第一个数据,导致初始化CheckBox的时候
将第一个条目的数据也改变了所以导致滑动回来后,之前选择的取消选择了
因此将初始化CheckBox状态的语句放在设置完监听事件后就正常了。