Creating a custom CursorAdapter for Android

I’ve been writing a bit more Android code, and came upon the need to write a custom CursorAdapter for a ListView, as the way I wanted to display data from a Cursor was dependent on relationships between different fields of the database.

Of the problems I encountered, the most obvious was when I tried to inflate views using View.inflate(), and found I would get the following error:

UnsupportedOperationException: addView(View, LayoutParams)
is not supported in AdapterView at android.widget.AdapterView

After a bit of rummaging around, I found that the following bit of code would work when attached to a ListView using setAdapter().

public class ExampleCursorAdapter extends CursorAdapter {
	public ExampleCursorAdapter(Context context, Cursor c) {
		super(context, c);
	}
 
	@Override
	public void bindView(View view, Context context, Cursor cursor) {
		TextView summary = (TextView)view.findViewById(R.id.summary);
		summary.setText(cursor.getString(
				cursor.getColumnIndex(ExampleDB.KEY_EXAMPLE_SUMMARY)));
	}
 
	@Override
	public View newView(Context context, Cursor cursor, ViewGroup parent) {
		LayoutInflater inflater = LayoutInflater.from(context);
		View v = inflater.inflate(R.layout.item, parent, false);
		bindView(v, context, cursor);
		return v;
	}
}

The above example code doesn’t actually require a CursorAdapter, it would easily be implemented using a SimpleCursorAdapter, but it serves to show the idea. Basicly, get a LayoutInflater from the context, and use the version of inflate() that does not attach to the root view.

3 thoughts on “Creating a custom CursorAdapter for Android

  1. tip

    Why do you call bindView() in newView()? It seems to then be called twice, at least on the emulator.
    Don’t see much info on CursorAdapter. Thanks for the info.

  2. Tiger

    suggestions:
    1. Move “LayoutInflater inflater = LayoutInflater.from(context);” to construction to avoid execute it every time.
    2. Calling bindView() from newView() is not necessary. bindView() will be called after newView() by the framework.

    A custom CursorAdapter from one of my projects:
    protected class ActivityCursorAdapter extends CursorAdapter {

    private LayoutInflater mInflater;
    private int mActivityIndex;
    private int mTimeIndex;
    private int mActionIndex;
    private int mAmountIndex;

    public ActivityCursorAdapter(Context context, Cursor c) {
    super(context, c);

    mActivityIndex = c.getColumnIndex(Notes.ACTIVITY);
    mTimeIndex = c.getColumnIndex(Notes.TIME);
    mActionIndex = c.getColumnIndex(Notes.ACTION);
    mAmountIndex = c.getColumnIndex(Notes.AMOUNT);

    mInflater = LayoutInflater.from(context);
    }

    @Override
    public void bindView(View view, Context context, Cursor cursor) {
    TextView activity = (TextView) view.findViewById(android.R.id.text1);
    TextView time = (TextView) view.findViewById(android.R.id.text2);
    TextView actionAndAmount = (TextView) view.findViewById(R.id.text3);

    activity.setText(cursor.getString(mActivityIndex));

    long lTime = cursor.getLong(mTimeIndex);
    Calendar cal = Calendar.getInstance();
    cal.setTimeInMillis(lTime);
    time.setText(cal.get(Calendar.HOUR_OF_DAY) + “:” + String.format(“%02d”, cal.get(Calendar.MINUTE)));

    String amount = cursor.getString(mAmountIndex);
    if ( amount.length() > 0){
    actionAndAmount.setText(cursor.getString(mActionIndex) + ” (” + amount + “)”);
    } else {
    actionAndAmount.setText(cursor.getString(mActionIndex));
    }
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
    return mInflater.inflate(R.layout.activityitem_list, null);
    }

    }

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>