CursorAdapter bindView optimization
Asked Answered
H

2

15

When overriding ArrayAdapter I know is correct using a pattern like this:

if(view != null){
   ...create new view setting fields from data 
}else
  return view; //reuse view

is correct too using this pattern with CursorAdapters? My problem is that I have a textcolor which can be red or blue according to a cursor field, so I don't want any errors like a red color on a cell which has a field needing blue color. My bindView code is something like this:

if(c.getString(2).equals("red"))
      textView.setTextColor(<red here>);
   else
      textView.setTextColor(<blue here>);

if I reuse view can I be sure that red goes on red, while blue goes on blue?

Hurter answered 31/8, 2012 at 22:39 Comment(0)
P
37

In CursorAdapter, you get layout in newView and bind data in bindView. CursorAdapter already do reuse pattern in getView so you don't have to do it again. Below is the original getView source code.

  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;
}

If you want further optimization using ViewHolder Pattern here is example: Create tag in newView and retrieve in bindView

    public class TimeListAdapter extends CursorAdapter {
     private LayoutInflater inflater;
     private    static  class   ViewHolder  {
         int    nameIndex;
         int    timeIndex;
         TextView   name;
         TextView   time;
    }
  public TimeListAdapter(Context context, Cursor c, int flags) {
    super(context, c, flags);
  this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  }
  @Override
  public void bindView(View view, Context context, Cursor cursor) {
         ViewHolder holder  =   (ViewHolder)    view.getTag();
         holder.name.setText(cursor.getString(holder.nameIndex));
         holder.time.setText(cursor.getString(holder.timeIndex));
  }
  @Override
  public View newView(Context context, Cursor cursor, ViewGroup  
  p parent) {
         View   view    =   inflater.inflate(R.layout.time_row, null);
         ViewHolder holder  =   new ViewHolder();
         holder.name    =   (TextView)  view.findViewById(R.id.task_name);
         holder.time    =   (TextView)  view.findViewById(R.id.task_time);
     holder.nameIndex   =   cursor.getColumnIndexOrThrow 
         (TaskProvider.Task.NAME);
         holder.timeIndex   =   cursor.getColumnIndexOrThrow    
         (TaskProvider.Task.DATE);
         view.setTag(holder);
    return view;
  }
}
Practise answered 1/9, 2012 at 3:45 Comment(3)
I would probably add LayoutInflater.from(context) as a global variable set in constructor, so it won't need to be got each time newView is run.Lisle
Is the ViewHolder still valid today? or is there a new simpler/different way?Aniseed
You can replace the ViewHolder pattern using view.setTag(int key,Object obj) and view.getTag(int key)Professor
A
2

Yes, getView is in Adapter and is not dependant from ArrayAdapter nor CursorAdapter.

recycling is always a good practice. Ensure that your code sets a colour in every situation.

Alkane answered 31/8, 2012 at 22:50 Comment(4)
start with textView.setTextColor(<default>) and then process colors like you doAlkane
Something like: if(view != null) view.setTextcolor(); else { <create the whole view> ?}Hurter
my pattern is rather if (view==null) {view=layoutinflater.inflate(...)} view.setText(...);Alkane
Or if your adapter inherits from SimpleCursorAdapter simply do view=super.getView(); view.setText(...) That way, it will be recycled and non-nullAlkane

© 2022 - 2024 — McMap. All rights reserved.