1

I have a ListView with android:choiceMode="multipleChoice". I fill this ListView from a Cursor through a SimpleCursorAdapter. Is there really no way to directly bind the "CheckBox" of the ListView's CheckedTextView layout to a boolean value from the cursor?

Currently I loop through the cursor calling ListView.setItemChecked() if the value is true:

private void showMyData(long myId) {
    // fill the list
    String[] fromColumns = { "myTextColumn" };
    int[] toViews = { android.R.id.text1 };
    Cursor myCursor = _myData.readData(myId);
    CursorAdapter myAdapter = new SimpleCursorAdapter(this,
        android.R.layout.simple_list_item_multiple_choice,
        myCursor, fromColumns, toViews);
    ListView myListView = (ListView) findViewById(R.id.myListView);
    myListView.setAdapter(myAdapter);
    // mark items that include the object specified by myId
    int myBooleanColumnPosition = myCursor
        .getColumnIndex("myBooleanColumn");
    for (int i = 0; i < myCursor.getCount(); i++) {
        myCursor.moveToPosition(i);
        if (myCursor.getInt(myBooleanColumnPosition ) == 1) {
            myListView.setItemChecked(i, true);
        }
    }
}

That does the job. But I would like to have code like this:

String[] fromColumns = { "myTextColumn", "myBooleanColumn" };
int[] toViews = { android.R.id.text1, android.R.id.Xyz };

and have no loop. Am I missing something here or is it Android?

EDIT: I tried this as suggested by Luksprog:

public boolean setViewValue(View view, Cursor cursor,
        int columnIndex) {
    CheckedTextView ctv = (CheckedTextView) view;
    ctv.setText(cursor.getString(cursor
            .getColumnIndex("myTextColumn")));
    if (cursor.getInt(cursor.getColumnIndex("myBooleanColumn")) == 1) {
        ctv.setChecked(true);
        Log.d("MY_TAG", "CheckBox checked");
    }
    return true;
}

That logged checking the CheckBox but didn't actually do it. Maybe that's a bug on my side. And while it's even more complicated than the initial loop at least it feels like one is using the framework, not working against it. So thank you Luksprog for the answer.

But to sum it up: Android is actually missing the straight forward approach.

Rhyme
  • 45
  • 4
  • Did you just use one `id` in the `toViews` array(just use the `android.R.id.text1`)? Also put an `else` clause where you set the checked state to unchecked. This should have worked at least visually in the list. Keep in mind that my answer will force the ListView to only keep the state of the CheckBoxes from the Cursor, any changes that you make would need to be seen by the Cursor to appear in the list. I would go with your initial approach a loop run once isn't something that bad. – user Nov 14 '12 at 19:58
  • simple_list_item_multiple_choice.xml contains only that single view (text1) - that's the problem. I'll stick with the loop as it seems to be the official way. I'm just learning the API and wanted to make shure I didn't miss something as this looping looks cobbled together. setItemChecked() updates a LongSparseArray and invokes a callback which I guess does nothing if an item isn't visible. So it seems OK to run this loop even for larger numbers of items. – Rhyme Nov 15 '12 at 15:31

1 Answers1

0

Use a SimpleCursorAdapter.ViewBinder on your adapter. Make sure your Cursor has the boolean values column in it and then:

String[] fromColumns = { "myTextColumn" };
int[] toViews = { android.R.id.text1 };
Cursor myCursor = _myData.readData(myId);
CursorAdapter myAdapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_multiple_choice, myCursor, fromColumns, toViews);
myAdapter.setViewBinder(new ViewBinder() {
       public boolean setViewValue (View view, Cursor cursor, int columnIndex) {
          // set the text of the list row, the view parameter (simple use cursor.getString(columnIndex))
          // set the CheckBox status(the layout used in the adapter is a CheckedTextView)
          return true;
       }
});
user
  • 86,916
  • 18
  • 197
  • 190
  • hey man, I am trying out method, exact same method. It throws error saying, "android.widget.TextView cannot be cast to android.widget.CheckBox". – Dushyant Patel Feb 15 '14 at 05:00
  • @DushyantPatel If you have more than one view in the list row then in the `setViewValue()` you need to look at the incoming view's id and bind the value only for the view with the specific view(in your case the view that has the id of the `TextView`). – user Feb 15 '14 at 07:20
  • @DushyantPatel use this to get the right view on column iteration: int checkboxIndex = cursor.getColumnIndexOrThrow("COLUMN_NAME"); if (columnIndex == checkboxIndex) { CheckBox cb = (CheckBox) view;;....... – Mohanad Haddadin Feb 21 '16 at 11:02