Android: Issue with newView and bindView in custom SimpleCursorAdapter Android: Issue with newView and bindView in custom SimpleCursorAdapter android android

Android: Issue with newView and bindView in custom SimpleCursorAdapter


Overriding the getView() function gives you the possibility of "re-using" already inflated list items (the list items that are "scrolled out" from the current view port when you scroll your list back and forth).

By doing so you'll save a lot of memory resources and processor run time, since inflating is a quite time consuming operation. For each and every convertView you re-use you also save GC run-time (since the garbage collector doesn't have to collect that specific list item).

You can also create a "view collection" class (the ViewHolder class in the below example) which will hold the references for each view in your inflated list item. This way you don't have to find them each and every time you update a list item with new values (typically whan you scroll the list). findViewById() is also a rather time consuming operation.

Also I think you can cache more variables, like the layout inflater, and the column indices. Everything to save time :-)

private final Context mContext;private final int mLayout;private final Cursor mCursor;private final int mNameIndex;private final int mIdIndex;private final LayoutInflater mLayoutInflater;private final class ViewHolder {    public TextView name;    public ImageView image;    public CheckBox checkBox;}public FriendAdapter(Context context, int layout, Cursor c, String[] from, int[] to) {    super(context, layout, c, from, to);    this.mContext = context;    this.mLayout = layout;    this.mCursor = c;    this.mNameIndex = mCursor.getColumnIndex(WhipemDBAdapter.KEY_NAME);    this.mIdIndex = mCursor.getColumnIndex(WhipemDBAdapter.KEY_FB_ID);    this.mLayoutInflater = LayoutInflater.from(mContext);}public View getView(int position, View convertView, ViewGroup parent) {    if (mCursor.moveToPosition(position)) {        ViewHolder viewHolder;        if (convertView == null) {            convertView = mLayoutInflater.inflate(mLayout, null);            viewHolder = new ViewHolder();            viewHolder.name = (TextView) convertView.findViewById(R.id.contact_name);            viewHolder.image = (ImageView) convertView.findViewById(R.id.contact_pic);            viewHolder.checkBox = (CheckBox) convertView.findViewById(R.id.checkbox);            convertView.setTag(viewHolder);        }        else {            viewHolder = (ViewHolder) convertView.getTag();        }        String name = mCursor.getString(mNameIndex);        String fb_id = mCursor.getString(mIdIndex);        Drawable drawable = LoadImageFromWebOperations("http://graph.facebook.com/"+fb_id+"/picture");        boolean isChecked = ((GlobalVars) mContext.getApplicationContext()).isFriendSelected(fb_id);        viewHolder.name.setText(name);        viewHolder.image.setImageDrawable(drawable);        viewHolder.checkBox.setTag(fb_id);        viewHolder.checkBox.setChecked(isChecked);    }    return convertView;}


The example is almost right. You don't need to do the binding in newView(), since like you mentioned, bindView() will be called. If you see the sequence newView/bindView called twice per item, you are probably using ListView with its height set to wrap_content, which is always a bad idea. Finally, newView() and bindView() are specific to CursorAdapter: it implements getView() and calls either newView() or bindView() for you. However, overriding getView() is perfectly valid as well. This is how other adapters work.

Note that getView() (and therefore bindView/newView) are only invoked for each item that will be displayed on the screen.