2010-12-31 3 views
27

Вот мой заказ CursorAdapter:Шаблон ViewHolder правильно реализован в пользовательском CursorAdapter?

public class TasksAdapter extends CursorAdapter implements Filterable { 

    private final Context context; 

    public TasksAdapter(Context context, Cursor c) { 
     super(context, c); 
     this.context = context; 
    } 

    /** 
    * @see android.widget.CursorAdapter#newView(android.content.Context, android.database.Cursor, android.view.ViewGroup) 
    */ 
    @Override 
    public View newView(Context context, Cursor cursor, ViewGroup parent) { 
     LayoutInflater inflater = LayoutInflater.from(context); 
     View v = inflater.inflate(android.R.layout.simple_list_item_checked, parent, false);   

     ViewHolder holder = new ViewHolder(); 
     holder.textview = (CheckedTextView)v.findViewById(android.R.id.text1); 
     v.setTag(holder); 

     return v; 
    } 

    /** 
    * @see android.widget.CursorAdapter#bindView(android.view.View, android.content.Context, android.database.Cursor) 
    */ 
    @Override 
    public void bindView(View view, Context context, Cursor cursor) { 

     ViewHolder holder = (ViewHolder)view.getTag(); 
     int titleCol = cursor.getColumnIndexOrThrow(Tasks.TITLE); 
     int completedCol = cursor.getColumnIndexOrThrow(Tasks.COMPLETED); 

     String title = cursor.getString(titleCol); 
     boolean completed = Util.intToBool(cursor.getInt(completedCol)); 

     holder.textview.setText(title); 
     holder.textview.setChecked(completed); 
    } 

    /** 
    * @see android.widget.CursorAdapter#runQueryOnBackgroundThread(java.lang.CharSequence) 
    */ 
    @Override 
    public Cursor runQueryOnBackgroundThread(CharSequence constraint) { 

     StringBuffer buffer = null; 
     String[] args = null; 

     if (constraint != null) { 
      buffer = new StringBuffer(); 
      buffer.append("UPPER ("); 
      buffer.append(Tasks.TITLE); 
      buffer.append(") GLOB ?"); 
      args = new String[] { "*" + constraint.toString().toUpperCase() + "*" }; 
     } 

     Cursor c = context.getContentResolver().query(Tasks.CONTENT_URI, 
      null, (buffer == null ? null : buffer.toString()), args, 
      Tasks.DEFAULT_SORT_ORDER); 

     c.moveToFirst(); 
     return c; 
    } 

    /** 
    * @see android.widget.CursorAdapter#convertToString(android.database.Cursor) 
    */ 
    @Override 
    public CharSequence convertToString(Cursor cursor) { 
     final int titleCol = cursor.getColumnIndexOrThrow(Tasks.TITLE); 
     String title = cursor.getString(titleCol); 
     return title; 
    } 

    static class ViewHolder { 
     CheckedTextView textview; 
    } 

} 

ли это падение в ограничение рисунка ViewHolder? Я не был уверен, потому что это был CursorAdapter, где не было getView. Если есть какие-либо проблемы или предложения, не могли бы вы указать их.

ответ

45

CursorAdapter не будет называть newView каждый раз, когда ему нужна новая строка; если он уже имеет View, он вызывается bindView, поэтому созданный вид на самом деле используется повторно.

Это, как указано Джозеф, в комментариях, вы все равно можете использовать ViewHolder, чтобы избежать повторного вызова findViewById.

Если вы все еще обеспокоены эффективностью, то посмотрите на SimpleCursorAdapter реализации, которая использует WeakHashMap (карту WeakReferences):

WeakHashMap<View, View[]> mHolders = new WeakHashMap<View, View[]>(); 
+2

Так что я могу сделать дорогие звонки как View.findViewById (INT) и мое приложение не будет отставать? –

+16

'findViewById (int)' не так дорого, как вы думаете. Он вернет только ссылку (если таковая существует). Метод ViewHolder существует для решения других проблем: не создавайте больше представлений, чем того, что вам действительно нужно (таким образом, это позволяет избежать чрезмерных инфляций зрения, что дорого). – Cristian

+1

@Cristian, спасибо. Я использовал 'newView' и' bindView', чтобы класс расширил 'SimpleCursorAdapter'. См. Код ниже. –

1

Моя реализация класса расширяет SimpleCursorAdapter с newView и bindView но без ViewHolder рисунка

private class CountriesAdapter extends SimpleCursorAdapter { 

      private LayoutInflater mInflater; 

      public CountriesAdapter(Context context, int layout, Cursor cursor, String[] from, 
        int[] to, LayoutInflater inflater) { 
       super(getActivity(), layout, cursor, from, to, CURSOR_ADAPTER_FLAGS); 
       mInflater = inflater; 
      } 

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

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

       TextView tvCountry = (TextView) rowView.findViewById(R.id.countriesList_tv_countryName); 
       TextView tvOrgs = (TextView) rowView.findViewById(R.id.countriesList_tv_orgNames); 
       ImageView ivContinent = 
         (ImageView) rowView.findViewById(R.id.countriesList_iv_continentName); 

       // TODO: set texts of TextViews and an icon here 
       } 

      } 
    } 
7

Если вы перекрывая newView() и bindView(), вам не нужно ничего делать в getView(). CursorAdapter имеет реализацию getView(), которая делегирует newView() и bindView() для обеспечения повторного использования строк.

findViewById() может быть вызвано часто во время прокрутки ListView, что может замедлить работу. Даже когда Adapter возвращает завышенный вид на переработку, вам все равно нужно искать элементы и обновлять их. Чтобы избежать этого, полезно использовать шаблон ViewHolder.

Вот пример ViewHolder шаблона реализован для приложения погоды:

public class ForecastAdapter extends CursorAdapter { 

    public ForecastAdapter(Context context, Cursor cursor, int flags) { 
     super(context, cursor, flags); 
    } 

    @Override 
    public View newView(Context context, Cursor cursor, ViewGroup parent) { 
     View view = LayoutInflater.from(context).inflate(
       R.layout.list_item_forecast, parent, false); 
     ViewHolder viewHolder = new ViewHolder(view); 
     view.setTag(viewHolder); 
     return view; 
    } 

    @Override 
    public void bindView(View view, Context context, Cursor cursor) { 
     ViewHolder viewHolder = (ViewHolder) view.getTag(); 

     long date = cursor.getLong(ForecastFragment.COL_WEATHER_DATE); 
     viewHolder.dateView.setText("Today"); 

     String weatherForecast = 
       cursor.getString(ForecastFragment.COL_WEATHER_DESC); 
     viewHolder.descriptionView.setText(weatherForecast); 

     double high = cursor.getFloat(ForecastFragment.COL_WEATHER_MAX_TEMP); 
     viewHolder.highTempView.setText("30"); 

     double low = cursor.getFloat(ForecastFragment.COL_WEATHER_MIN_TEMP); 
     viewHolder.lowTempView.setText("24"); 

     int weatherConditionId = 
       cursor.getInt(ForecastFragment.COL_WEATHER_CONDITION_ID); 
     viewHolder.iconView.setImageResource(R.drawable.ic_snow); 
    } 

    /** Cache of the children views for a list item. */ 
    public static class ViewHolder { 
     public final ImageView iconView; 
     public final TextView dateView; 
     public final TextView descriptionView; 
     public final TextView highTempView; 
     public final TextView lowTempView; 

     public ViewHolder(View view) { 
      iconView = 
        (ImageView) view.findViewById(R.id.item_icon); 
      dateView = 
        (TextView) view.findViewById(R.id.item_date_textview); 
      descriptionView = 
        (TextView) view.findViewById(R.id.item_forecast_textview); 
      highTempView = 
        (TextView) view.findViewById(R.id.item_high_textview); 
      lowTempView = 
        (TextView) view.findViewById(R.id.item_low_textview); 
     } 
    } 
} 
Смежные вопросы