This is because when you scroll a listview it actually re-uses the rows to display the information. This greatly improves the performance of scrolling through long lists.
But that aside, lets get it fixed. What you need to do is trigger an event when the checkbox is selected so the value can be stored in the array, most suitably with the rest of the list information, so that when the view is shown again the value can be restored, as well as correctly clearing the checked state when the View is re-used.
This can all be done inside the getView() method within your custom ArrayAdapter.
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
if(row == null) {
LayoutInflater inflater = LayoutInflater.from(this.getContext());
row = inflater.inflate(R.layout.category_color, parent, false);
}
if(this.getCount() > position) {
DataObject data = this.getItem(position);
CheckBox checkbox = (CheckBox)row.findViewById(R.id.checkbox);
checkbox.setChecked(data.isChecked());
checkbox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
data.setChecked(isChecked);
}});
...
}
return(row);
}