Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I have a custom CursorAdapter that populates a ListView of Tasks from my database. Each ListView item has a checkbox and a button in it. When pressing the checkbox, the database gets updated to set the task as completed. The problem is that when exiting the ListActivity and returning to the Task list, nothing is updated and the checkboxes don't retain their state.

I have included my CursorAdapter which is where the problem is I think. Is it something to do with the recycling of views maybe? Any help would be much appreciated.

public class ScheduleListAdapter extends CursorAdapter implements 
OnClickListener, OnCheckedChangeListener
{
private final static String TAG         = "FS: ScheduleList";

private LayoutInflater      inflater    = null;
private ListView            listView    = null;

private DataManager         db          = null;
private ContentValues       values      = null;

private boolean             isCompleted = false;

public ScheduleListAdapter(Context context, Cursor c, ListView listView, DataManager db)
{
    super(context, c);

    this.listView = listView;
    this.db = db;

    // Cache the inflater, avoids asking for a new one each time
    inflater = LayoutInflater.from(context);
}

/** Determines which button is clicked **/
@Override
public void onClick(View v)
{
    final int position = listView.getPositionForView(v);

    if (position != ListView.INVALID_POSITION)
    {
        Logger.e(TAG, "Button clicked at position: " + position);
    }
}

/** Determines which star is checked **/
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
{
    final int newValue;
    final int position = listView.getPositionForView(buttonView);

    if (position != ListView.INVALID_POSITION)
    {
        buttonView.setChecked(isChecked);

        if (isChecked)
        {
            newValue = 1;
        }
        else
        {
            newValue = 0;
        }

        values = new ContentValues();
        values.put(ScheduleTable.KEY_COMPLETED, newValue);
        db.update(ScheduleTable.TABLE_NAME, values, position);

        // refresh(db.rawQueryGetAll(ScheduleTable.TABLE_NAME));
    }
}

/** Makes a new view to hold the data pointed to by cursor. **/
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent)
{
    // Create and inflate the listView item view here
    View view = inflater.inflate(R.layout.schedule_list_item, parent, false);

    ViewHolder holder = new ViewHolder();

    holder.cbxCheck = (CheckBox) view.findViewById(R.id.cbx_completed);
    holder.txvText1 = (TextView) view.findViewById(R.id.txv_taskListTitle);
    holder.txvText2 = (TextView) view.findViewById(R.id.txv_taskListSubTitle1);
    holder.txvText3 = (TextView) view.findViewById(R.id.txv_taskListSubTitle2);
    holder.btnButton = (Button) view.findViewById(R.id.btn_Edit);
    holder.btnButton.setOnClickListener(this);
    holder.cbxCheck.setOnCheckedChangeListener(this);

    view.setTag(holder);

    return view;
}

/** Bind an existing view to the data pointed to by cursor **/
@Override
public void bindView(View view, Context context, Cursor cursor)
{
    // Populate list from the cursor here
    ViewHolder holder = (ViewHolder) view.getTag();

    // Bind the data efficiently with the holder
    holder.txvText1.setText(cursor.getString(cursor.getColumnIndex(ScheduleTable.KEY_TITLE)));
    holder.txvText2.setText(cursor.getString(cursor.getColumnIndex(ScheduleTable.KEY_DESC)));
    holder.txvText3.setText(cursor.getString(cursor.getColumnIndex(ScheduleTable.KEY_DATE)));
    isCompleted = Utils.intToBool(cursor.getInt(cursor.getColumnIndex(ScheduleTable.KEY_COMPLETED)));

    holder.cbxCheck.setOnCheckedChangeListener(null);
    holder.cbxCheck.setChecked(isCompleted);
    holder.cbxCheck.setOnCheckedChangeListener(this);

    Logger.e(TAG, cursor.getString(cursor.getColumnIndex(ScheduleTable.KEY_TITLE)) + " at position is completed: " + isCompleted);
}

/** Updates the listView when data changes **/
public void refresh(Cursor newCursor)
{
    changeCursor(newCursor);
    notifyDataSetChanged();
}

private static class ViewHolder
{
    TextView    txvText1;
    TextView    txvText2;
    TextView    txvText3;
    CheckBox    cbxCheck;
    Button      btnButton;
}

}
share|improve this question
1. I doubt that listView.getPositionForView(buttonView) will anytime return the position. I would pass the position in holder.cbxCheck.setTag... in bindView. 2. The cursor might not be requered when db changes/updates. Must be some container doubling db values. Set ListView multiple choice and use setCheckedItem/getCheckedItemPositions to store checked state info (no need to requery after each db update). If the container has a value then set else set value from the cursor in bindView. setItemChecked in the listener etc. 3. I don't think that "position" uniquely identifies a row in db. _id? – Deucalion Apr 23 '12 at 14:18
Thanks for replying. I have tested the listView.getPositionForView and it returns the correct position of the checkbox, which corresponds to the correct row in the database. Calling the refresh method does not update either (I commented it out in onCheckedChanged). Haven't seen the ListView multiple choice before, I'll look into that. Thanks – Daimo-S Apr 23 '12 at 14:49
But the documentation for getPositionForView is somewhat unclear. It does not says that it will search in row/item children views. Add Log.i/w/d here and there and look if the db is updated successfully and other points. – Deucalion Apr 23 '12 at 15:13

Know someone who can answer? Share a link to this question via email, Google+, Twitter, or Facebook.

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.