Android save Checkbox State in ListView with Cursor Adapter
I cant find a way to save the checkbox state when using a Cursor adapter. Everything else works fine but if i click on a checkbox it is repeated when it is recycled. Ive seen examples using array adapters but because of my lack of experience im finding it hard to translate it into using a cursor adapter. Could someone give me an example of how to go about it. Any help appreciated.
private class PostImageAdapter extends CursorAdapter {
private static final int s = 0;
private int layout;
Bitmap bm=null;
private String PostNumber;
TourDbAdapter mDbHelper;
public PostImageAdapter (Context context, int layout, Cursor c, String[] from, int[] to, String Postid) {
super(context, c);
this.layout = layout;
PostNumber = Postid;
mDbHelper = new TourDbAdapter(context);
mDbHelper.open();
}
@Override
public View newView(Context context, final Cursor c, ViewGroup parent) {
ViewHolder holder;
LayoutInflater inflater=getLayoutInflater();
View row=inflater.inflate(R.layout.image_post_row, null);
holder = new ViewHolder();
holder.Description = (TextView) row.findViewById(R.id.item_desc);
holder.cb = (CheckBox) row.findViewById(R.id.item_checkbox);
holder.DateTaken = (TextView) row.findViewById(R.id.item_date_taken);
holder.Photo = (ImageView) row.findViewById(R.id.item_thumb);
row.setTag(holder);
int DateCol = c.getColumnIndex(TourDbAdapter.KEY_DATE);
String Date = c.getString(DateCol);
int DescCol = c.getColumnIndex(TourDbAdapter.KEY_CAPTION);
String Description = c.getString(DescCol);
int FileNameCol = c.getColumnIndex(TourDbAdapter.KEY_FILENAME);
final String FileName = c.getString(FileNameCol);
int PostRowCol = c.getColumnIndex(TourDbAdapter.KEY_Post_ID);
String RowID = c.getString(PostRowCol);
String Path = "sdcard/Tourabout/Thumbs/" + FileName + ".jpg";
Bitmap bm = BitmapFactory.decodeFile(Path, null);
holder.Photo.setImageBitmap(bm);
holder.DateTaken.setText(Date);
holder.Description.setText(Description);
holder.cb.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
CheckBox cBox = (CheckBox) v;
if (cBox.isChecked()) {
mDbHelper.UpdatePostImage(FileName, PostNumber);
}
else if (!cBox.isChecked()) {
mDbHelper.UpdatePostImage(FileName, "");
}
}
});
return row;
};
@Override
public void bindView(View row, Context context, final Cursor c) {
ViewHolder holder;
holder = (ViewHolder) row.getTag();
int DateCol = c.getColumnIndex(TourDbAdapter.KEY_DATE);
String Date = c.getString(DateCol);
int DescCol = c.getColumnIndex(TourDbAdapter.KEY_CAPTION);
String Description = c.getString(DescCol);
int FileNameCol = c.getColumnIndex(TourDbAdapter.KEY_FILENAME);
final String FileName = c.getString(FileNameCol);
int PostRowCol = c.getColumnIndex(TourDbAdapter.KEY_Post_ID);
String RowID = c.getString(PostRowCol);
String Path = "sdcard/Tourabout/Thumbs/" + FileName + ".jpg";
Bitmap bm = BitmapFactory.decodeFile(Path, null);
File x = null;
holder.Photo.setImageBitmap(bm);
holder.DateTaken.setText(Date);
holder.Description.setText(Description);
holder.cb.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
CheckBox cBox = (CheckBox) v;
if (cBox.isChecked()) {
mDbHelper.UpdatePostImage(FileName, PostNumber);
}
else if (!cBox.isChecked()) {
mDbHelper.UpdatePostImage(FileName, "");
}
}
});
}
}
static class ViewHolder{
TextView Description;
ImageView Photo;
CheckBox cb;
TextView DateTaken;
}
}
I had the same issue myself: how to toggle multiple select CheckedTextView in a custom layout (i.e not using android.R.layout.simple_list_item_multiple_choice)
The following worked for me. The example I have is a custom view that is provided an adaptor extended from SimpleCursorAdapter.
My custom view (row_contact.xml):
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content" android:layout_width="fill_parent">
<CheckedTextView
android:id="@android:id/text1"
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:textAppearance="?android:attr/textAppearanceLarge"
android:gravity="center_vertical"
android:paddingLeft="6dip"
android:paddingRight="6dip"
android:checkMark="?android:attr/listChoiceIndicatorMultiple"
/>
<TextView
android:text="@+id/TextView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tvNumber"
android:layout_gravity="bottom"
android:paddingLeft="6dip"
android:paddingRight="6dip"
/>
</FrameLayout>
The adaptor is created in ListActivity.OnCreate, which calls setupViews():
private void setupViews() {
bOk = (Button) findViewById(R.id.ButtonOK);
bCancel = (Button) findViewById(R.id.ButtonCancel);
FListView = getListView();
//
bOk.setText("Select");
//
FListView.setItemsCanFocus(false);
FListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
//
bOk.setOnClickListener(this);
bCancel.setOnClickListener(this);
//
ContentResolver content = getContentResolver();
Cursor cursor = ApplicationHelper.MobilePhoneContacts(content);
startManagingCursor(cursor);
ListAdapter adapter = new CheckedCursorAdapter( SelectContacts.this, R.layout.row_contact, cursor,
new String[] {People.NAME, People.NUMBER},
new int[] {android.R.id.text1, R.id.tvNumber});
setListAdapter(adapter);
}
The Custom adaptor:
public class CheckedCursorAdapter extends SimpleCursorAdapter {
Activity context;
Cursor c;
public CheckedCursorAdapter(Activity context, int rowContact, Cursor cursor, String[] strings, int[] is) {
super(context, rowContact, cursor, strings, is);
this.context = context;
this.c = cursor;
}
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
ContactRowWrapper wrapper;
if (row == null) {
LayoutInflater inflater=context.getLayoutInflater();
row = inflater.inflate(R.layout.row_contact, null);
//
wrapper = new ContactRowWrapper(row);
row.setTag(wrapper);
} else {
wrapper = (ContactRowWrapper)row.getTag();
}
c.moveToPosition(position);
wrapper.getTextView().setText( c.getString(c.getColumnIndex(Contacts.People.NUMBER)) );
wrapper.getcheckBox().setText( c.getString(c.getColumnIndex(Contacts.People.NAME)) );
wrapper.getcheckBox().setChecked(getListView().isItemChecked(position));
//
return row;
}
}
The crucial bit of code for for me was to get check boxes working was:
wrapper.getcheckBox().setChecked(getListView().isItemChecked(position));
Hope this helps you or anyone else who stumbles onto this question.
Also, pardon my Java noobness... I've only started Java a few weeks ago.
I would recommend you use Android's built-in support for multiple-choice lists (CHOICE_MODE_MULTIPLE
).
The List11.java
SDK sample demonstrates this. You can also find a project from one of my tutorials that uses it here.
You can still use this technique with your own layout, so long as you include a CheckedTextView
with android:id="@android:id/text1"
as shown in the android.R.layout.simple_list_item_multiple_choice
resource, a copy of which ships with your SDK.
Also, see this question and this question and this question and this question.