HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMajor

Custom CursorAdapter Design

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
customdesigncursoradapter

Problem

Here's the code which I use for my Android custom cursor adapter which I use to bind data to my list view.

public class MessageAdapter extends CursorAdapter {
   private Cursor mCursor;
   private Context mContext;
   private final LayoutInflater mInflater;

    public MessageAdapter(Context context, Cursor c) {
        super(context, c);
        mInflater=LayoutInflater.from(context);
    mContext=context;
    }

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

        TextView mobileNo=(TextView)view.findViewById(R.id.mobileNolistitem);
        mobileNo.setText(cursor.getString(cursor.getColumnIndex(TextMeDBAdapter.KEY_MOBILENO)));

        TextView frequency=(TextView)view.findViewById(R.id.frequencylistitem);
        frequency.setText(cursor.getString(cursor.getColumnIndex(TextMeDBAdapter.KEY_FREQUENCY)));

        TextView rowid=(TextView)view.findViewById(R.id.rowidlistitem);
        rowid.setText(cursor.getString(cursor.getColumnIndex(TextMeDBAdapter.KEY_ID)));

    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        final View view=mInflater.inflate(R.layout.message_list_item,parent,false); 
        return view;
    }

}


I know that there's another efficient way to do this which reuses the list item instantiated. Can someone tell me how?

Solution

This is exactly* the way you should be using your CursorAdapter. I'm sure you're referring to "recycling" the Views as talked about when overriding the getView() method of a BaseAdapter.

In the case of the CursorAdapter, all of that is taken care of for you so that just implementing newView() and bindView() fully takes advantage of the View recycling you're asking about.

Here is the code for CursorAdapter.getView():

public View getView(int position, View convertView, ViewGroup parent) {
    if (!mDataValid) {
        throw new IllegalStateException("this should only be called when the cursor is valid");
    }
    if (!mCursor.moveToPosition(position)) {
        throw new IllegalStateException("couldn't move cursor to position " + position);
    }
    View v;
    if (convertView == null) {
        v = newView(mContext, mCursor, parent);
    } else {
        v = convertView;
    }
    bindView(v, mContext, mCursor);
    return v;
}


So you see, the method attempts to recycle the View that was passed in by checking convertView == null. If successful, it uses that View and simply calls bindView() to set it up appropriately. If convertView is null, it calls newView() to create the View, followed by bindView() to set it up. This is one of the rare instances on SE that I can say "You're doing it right!"

  • But to nitpick, there's really no reason to maintain a reference to your Context in mContext - You're not using it anywhere and maintaining references to Contexts can lead to memory leaks, and ultimately the end of the world.

Code Snippets

public View getView(int position, View convertView, ViewGroup parent) {
    if (!mDataValid) {
        throw new IllegalStateException("this should only be called when the cursor is valid");
    }
    if (!mCursor.moveToPosition(position)) {
        throw new IllegalStateException("couldn't move cursor to position " + position);
    }
    View v;
    if (convertView == null) {
        v = newView(mContext, mCursor, parent);
    } else {
        v = convertView;
    }
    bindView(v, mContext, mCursor);
    return v;
}

Context

StackExchange Code Review Q#1057, answer score: 24

Revisions (0)

No revisions yet.