I have a custom ListView
where clicking an item fires a new Activity
.
Each row of the ListView
has a CheckBox
and a TextView
.
This is the getView
method from my custom ListView
:
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.puzzles_row, null);
}
ListedPuzzle lp = items.get(position);
if (lp != null) {
TextView title = (TextView) v.findViewById(R.id.listTitles);
title.setText(lp.getTitle());
CheckBox star = (CheckBox) v.findViewById(R.id.star_listed);
star.setChecked(lp.isStarred());
star.setTag(new Integer(position));
star.setOnCheckedChangeListener(new OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
Integer realPosition = (Integer) buttonView.getTag();
ListedPuzzle obj = items.get(realPosition);
starListedPuzzle(obj.getId(), isChecked);
}
});
}
return v;
}
The onCheckedChanged
is called when coming back from the another Activty, without possible user interaction to actually check anything.
The point is that used to work fine and haven't really change anything. I've read that it's a bug but can't really believe it.
It always calls the method on the same two items of the ListView
. Could they be set to checkedChange=true
somehow?
I have a feeling it is happening in the onRestoreInstanceState
method. Android automatically handles restoring the state of most View
s in your activity when it is paused and resumed. When being resumed, it sounds like it's restoring the checked state of your CheckBox
objects, which is triggering onCheckedChanged
. Try doing this in your Activity
and let me know if this solves your problem:
private boolean mRestoringInstanceState;
@Override
protected void onRestoreInstanceState( Bundle savedInstanceState ) {
mRestoringInstanceState = true;
super.onRestoreInstanceState( savedInstanceState );
mRestoringInstanceState = false;
}
Then change your onCheckChanged
method like so:
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
if(!mRestoringInstanceState) {
Integer realPosition = (Integer) buttonView.getTag();
ListedPuzzle obj = items.get(realPosition);
starListedPuzzle(obj.getId(), isChecked);
}
}
Edit: Probably a better/easier solution would be to assign the listener in the onResume
method instead since it gets called after onRestoreInstanceState
. Note that you wouldn't implement any of the above if using this solution:
@Override
protected void onResume() {
super.onResume();
CheckBox star = (CheckBox) v.findViewById(R.id.star_listed);
star.setOnCheckedChangeListener(new OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
// onCheckedChanged implementation
}
});
}
Edit2: Just realized you're doing this in an Adapter
. This may not be related to onRestoreInstanceState
, but I think I see the problem. You are reusing View
s in the Adapter
, which is good, but you're setting star
to checked before setting the listener. The problem is that star
already has a listener from the last time it came through the getView
method. Before you call star.setChecked()
, call star.setOnCheckedChangedListener(null)
and see if that solves your problem.