Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

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?

share|improve this question
    
I'm still getting started on Android apps. What list item are you refering to? –  Michael K Mar 1 '11 at 18:51
    
I'm referring to the list items in the list.See this video by Romain guy on making a good and efficient list view youtube.com/watch?v=N6YdwzAvwOA , although it's pretty long. –  rogerstone Mar 1 '11 at 19:50
add comment

2 Answers

up vote 17 down vote accepted

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.
share|improve this answer
    
One more thing You should definitely use - save pointers to all views with a ViewHolder, in order not to findViewById every time. –  paiNie Jan 6 '12 at 20:44
add comment

It would be even easier to use a SimpleCursorAdapter, but the exact same principal applies for CursorAdapter. You can cache the calls to findViewById() on the view and even getColumnIndex on the cursor by storing the data in the views tag. Using this stopped by ListView rendering slowly.

The ViewHolder pattern is borrowed from Efficient Adapter API demo here.

public static class CustomSimpleCursorAdapter extends SimpleCursorAdapter {

    /* constructor(); */

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

        ViewHolder holder = (ViewHolder) view.getTag();
        if (holder == null) {
            holder = new ViewHolder();
            holder.textView1 = (TextView) view.findViewById(R.id.text1);
            holder.textView2 = (TextView) view.findViewById(R.id.text2);
            holder.column1 = cursor.getColumnIndexOrThrow("column1");
            holder.column2 = cursor.getColumnIndexOrThrow("column2");
            view.setTag(holder);
        }

        holder.textView1.setText(cursor.getString(holder.column1));
        holder.textView2.setText(cursor.getString(holder.column2));
    }

    static class ViewHolder {
        TextView textView1;
        TextView textView2;
        int column1; 
        int column2;
    }
}
share|improve this answer
    
THe ViewHolder is the concept to go with, it costs a little bit of ram, but speeds up the binding of the view. @Tom Curran: Though I don't understand why you would get and keep the column index for every view, you should get it in the constructor and put in in two final fields! –  MrSnowflake May 31 '12 at 12:31
add comment

protected by syb0rg Mar 1 at 23:48

Thank you for your interest in this question. Because it has attracted low-quality answers, posting an answer now requires 10 reputation on this site.

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.