views:

2744

answers:

3

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;
}
}
A: 

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.

CommonsWare
How would i use my own layout? doesnt the checkedtextview need to be the top level of the row? I cant seem to find a way to add the views i need to have, such as an ImageView to show an image (photo from camera), when i use a checkedtextview.
Ricardo
First, `CheckedTextView` supports `android:drawableLeft` and kin, which you could use. Second, AFAIK, so long as it has the proper `android:id` (see above), it can be inside some other layout (e.g., a `LinearLayout` also involving an `ImageView`).
CommonsWare
now i seem to have the same problem as in this thread http://www.mail-archive.com/[email protected]/msg06941.html. How would i set the android:drawableLeft property from the code behind?
Ricardo
Call `setCompoundDrawables()` or one of the flavors of `setCompoundDrawablesWithIntrinsicBounds()`
CommonsWare
Thanks for your help. Ive decided to use the multiselect method and went with just the CheckedTextView in the xml and adding the image via setCompoundDrawablesWithIntrinsicBounds(). Still wasnt able to get the layout to work properly when using other views with CheckedTextView but this will do. This has been such a hassle for something that should be relatively simple. Thanks again.
Ricardo
A: 

Hi Ricardo

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.

Nazar
A: 

What is ContactRowWrapper in the above example???

Hades