2010-12-31 10 views
27

Ecco il mio CursorAdapter personalizzato:Il modello ViewHolder è stato implementato correttamente in CursorAdapter personalizzato?

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

} 

fa questo autunno nei vincoli del modello ViewHolder? Non ero sicuro perché questo era un CursorAdapter, dove non c'era getView. Se ci sono problemi o suggerimenti, potresti per favore indicarli.

risposta

45

CursorAdapter non chiamerà il newView ogni volta che ha bisogno di una nuova riga; se ha già un View, chiamerà lo bindView, quindi la vista creata verrà effettivamente riutilizzata.

Detto questo, come indicato da Joseph nei commenti, è comunque possibile utilizzare ViewHolder per evitare di chiamare ripetutamente lo findViewById.

Se siete ancora preoccupati per l'efficienza allora date un'occhiata al SimpleCursorAdapter attuazione, che utilizza una (una mappa di WeakReferences) WeakHashMap:

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

Così posso effettuare chiamate costose come View.findViewById (int) e la mia domanda non sarà in ritardo? –

+16

'findViewById (int)' non è costoso come pensi. Restituirà solo un riferimento (se esiste). La tecnica ViewHolder esiste per risolvere altri tipi di problemi: non creare più Views rispetto a ciò di cui hai realmente bisogno (evitando così eccessive inflazioni di visualizzazione, che sono costose). – Cristian

+1

@ Cristiano, grazie. Ho usato 'newView' e' bindView' per fare in modo che una classe estenda 'SimpleCursorAdapter'. Guarda il codice qui sotto. –

1

mia implementazione di una classe estende SimpleCursorAdapter con newView e bindView ma senza scheda di 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

Se sono prioritarie in newView() e bindView(), non è necessario fare nulla in più in getView(). CursorAdapter ha un'implementazione di getView() che delega a newView() e bindView() per far rispettare il riciclaggio di riga.

findViewById() forse chiamato frequentemente durante lo scorrimento di ListView, che può rallentare le prestazioni. Anche quando Adapter restituisce una visualizzazione gonfiata per il riciclaggio, è comunque necessario cercare gli elementi e aggiornarli. Per evitare ciò, è utile il modello ViewHolder.

Ecco un esempio di ViewHolder modello implementato per un'applicazione meteo:

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); 
     } 
    } 
} 
Problemi correlati