Grippie Grippie -4 years ago 139
Android Question

How do I maintain android checkbox state after scrolling

I've scoured multiple questions on this and still have not found the way to implement what i'm looking for. I have a simple custom cursorAdapter that is in the form

|textview checkbox|

when scrolling the checkboxes lose state when recycled. I have tried using an arrayList to store the boolean values but when checking them, it does not seem to ever come back as true.

public class BrowseCardsAdapter extends CursorAdapter {

private LayoutInflater mInflater = null;
private Context mContext;
public DataBaseHelper myDbHelper = null;

public BrowseCardsAdapter(Context context, Cursor cursor) {
super(context, cursor, true);
mInflater = LayoutInflater.from(context);
mContext = context;

myDbHelper = new DataBaseHelper(mContext);

try {
myDbHelper.openDataBaseForUpdate();
} catch (SQLException sqle) {
throw sqle;
}
}

@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {

return mInflater.inflate(R.layout.list_cards, parent, false);

}

@Override
public void bindView(final View view, final Context context, final Cursor cursor) {

final CheckBox cb_have = (CheckBox) view.findViewById(R.id.cb_have);
TextView cardNumber = (TextView) view.findViewById(R.id.tv_cardnumber);

final String cardNumberText = cursor.getString(cursor.getColumnIndex("CardNumber"));
final String have = cursor.getString(cursor.getColumnIndex("Have"));

cardNumber.setText(cardNumberText);

if (have.compareTo("true") == 0)
cb_have.setChecked(true);
else
cb_have.setChecked(false);

cb_have.setOnClickListener(new OnClickListener() {

public void onClick(View v) {

if (cb_have.isChecked()) {
myDbHelper.addHaveToDatabase(cardNumberText, true);
cb_have.setChecked(true);
}
else {
myDbHelper.addHaveToDatabase(cardNumberText, false);
cb_have.setChecked(false);
}
myDbHelper.close();
});


}

i'm storing the have state in the database, then i want to check the have state to set the checkbox. this way, when the users comes into the activity they will see items they have previously selected, as well as any new selections. This works great except for the scenario of scrolling views offscreen that lose state of newly selected items. could someone give me some pointers on how to save the state?

Answer Source

try going back to using a collection. writing to the database in increments like that is ill-advised.

Here:

    public class BrowseCardsAdapter extends CursorAdapter {

        private LayoutInflater mInflater = null;
        private boolean[] arrCb;

        public BrowseCardsAdapter(Context context, Cursor cursor) {
            super(context, cursor, true);
            mInflater = LayoutInflater.from(context);

            arrCb = new boolean[cursor.getCount()];
            for (int i = 0; i < arrCb.length; i++) {
                arrCb[i] = false;
            }
            // ^otherwise you can loop through the database (in your activity)
            // to fill this array with the correct values and pass it as a parameter
            // it'd look like initCb() below;
        }

/*      private boolean[] initCb() {
            Cursor cursor = myDbHelper.query(query statement);
            boolean[] arr = new boolean[cursor.getCount()];
            int i = 0;  
            while (cursor.moveToNext()) {
                arr[i] = cursor.getString(cursor.getColumnIndex("Have"));
                // ^obviously you'd need to convert your value to boolean however
                i++;
            }
            return arr;
        }*/

        @Override
        public View newView(Context context, Cursor cursor, ViewGroup parent) {

            return mInflater.inflate(R.layout.list_cards, parent, false);

        }

        @Override
        public void bindView(final View view, final Context context, final Cursor cursor) {

            final CheckBox cb_have     = (CheckBox) view.findViewById(R.id.cb_have);
            TextView cardNumber        = (TextView) view.findViewById(R.id.tv_cardnumber);

            final String cardNumberText  = cursor.getString(cursor.getColumnIndex("CardNumber"));       
//          final String have = cursor.getString(cursor.getColumnIndex("Have"));

            cardNumber.setText(cardNumberText);

            cb_have.setChecked(arrCb[cursor.getPosition()]);    
            cb_have.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    if (cb_have.isChecked()) {
                        arrCb[cursor.getPosition()] = true;
                    } else {
                        arrCb[cursor.getPosition()] = false;                        
                    }
                }
            });

        }
    }

two methods of filling the collection are offered. As for your technique, because you are constantly writing to the database, you can't get your values using the old cursor that the adapter was made with. you must re-instantiate the cursor upon each row load. Surely these requirements will make you give it up.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download