I'm trying to bind data from my SQLiteDatabase to a ListView. I'm currently using a SimpleCursorAdapter to fill in my ListView. Unfortunately this doesn't seem to work with setting a CheckBox's checked attribute.

This is how I do it now; instead of changing the CheckBox's checked status the adapter is filling in the value to the text argument, so the value is displayed right of the CheckBox as text.

Java:

setListAdapter( new SimpleCursorAdapter( this,
      R.layout.mylist,
      data,
      new String[] { Datenbank.DB_STATE, Datenbank.DB_NAME },
      new int[] { R.id.list_checkbox, R.id.list_text }
    ) );

mylist.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:id="@+id/LinearLayout01"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
>

<CheckBox android:text=""
    android:id="@+id/list_checkbox"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:checked="false"
    ></CheckBox>

<TextView android:text=""
    android:id="@+id/list_text"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    ></TextView>

</LinearLayout>

Edit: The field in the database is of course of type boolean and I've also tried to assign an id to the checked field to fill the value in.

Solution 1

You could set a custom SimpleCursorAdapter.ViewBinder:

SimpleCursorAdapter cursorAdapter = new SimpleCursorAdapter(/* ur stuff */);
cursorAdapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
    public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
        if(columnIndex == 1) {
            CheckBox cb = (CheckBox) view;
            cb.setChecked(cursor.getInt(1) > 0);
            return true;
        }
        return false;
    }
});

The setViewValue method is invoked for every column you specify in the SimpleCursorAdapter constructor and gives you a good place to manipulate some (or all) of the views.

Solution 2

I'm not sure how you would do this aside from creating a custom Adapter that overrode newView/bindView or getView, depending on what you override (ResourceCursorAdapter is a good one).

Ok, so here's an example. I didn't test to see if it would compile because I'm at work, but this should definitely point you in the right direction:

public class MyActivity extends ListActivity {

    MyAdapter mListAdapter;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Cursor myCur = null;

        myCur = do_stuff_here_to_obtain_a_cursor_of_query_results();

        mListAdapter = new MyAdapter(MyActivity.this, myCur);
        setListAdapter(mListAdapter);
    }


    private class MyAdapter extends ResourceCursorAdapter {

        public MyAdapter(Context context, Cursor cur) {
            super(context, R.layout.mylist, cur);
        }

        @Override
        public View newView(Context context, Cursor cur, ViewGroup parent) {
            LayoutInflater li = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            return li.inflate(R.layout.mylist, parent, false);
        }

        @Override
        public void bindView(View view, Context context, Cursor cur) {
            TextView tvListText = (TextView)view.findViewById(R.id.list_text);
            CheckBox cbListCheck = (CheckBox)view.findViewById(R.id.list_checkbox);

            tvListText.setText(cur.getString(cur.getColumnIndex(Datenbank.DB_NAME)));
            cbListCheck.setChecked((cur.getInt(cur.getColumnIndex(Datenbank.DB_STATE))==0? false:true))));
        }
    }
}

Solution 3

You can solve that problem by creating a custom CheckBox widget like so:

package com.example.CustomCheckBox;    
public class CustomCheckBox extends CheckBox {
     public CustomCheckBox(Context context, AttributeSet attrs, int defStyle) {
      super(context, attrs, defStyle);
     }
     public CustomCheckBox(Context context, AttributeSet attrs) {
      super(context, attrs);
     }
     public CustomCheckBox(Context context) {
      super(context);
     }
     protected void onTextChanged(CharSequence text, int start, int before, int after) {
      if (text.toString().compareTo("") != 0) {
       setChecked(text.toString().compareTo("1") == 0 ? true : false);
       setText("");
      }
     }
    }

The onTextChanged function will be called when the ListView binds the data to the CheckBox (ie. Adding either "0" or "1"). This will catch that change and add in your boolean processing. The 1st "if" statement is needed so as to not create infinite recursion.

Then provide your custom class in to the layout file as such:

<com.example.CustomCheckBox
 android:id="@+id/rowCheckBox"
 android:layout_height="fill_parent"
 android:layout_width="wrap_content" />

That should do it!