2010-12-31 2 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 패턴의 제약으로 올 가을? 나는 이것이 getView이없는 CursorAdapter 였기 때문에 확실하지 않았습니다. 문제 나 제안 사항이 있으면 알려주십시오.

답변

45

CursorAdapter은 새 행이 필요할 때마다 newView을 호출하지 않습니다. View이 이미있는 경우 bindView을 호출하므로 실제로 만들어진보기가 다시 사용됩니다.

의견에서 Joseph으로 지적했듯이 findViewById을 반복적으로 호출하는 것을 피하기 위해 ViewHolder를 계속 사용할 수 있습니다.

당신은 여전히 ​​다음 WeakHashMap (WeakReferences의지도)를 사용하는 SimpleCursorAdapter 구현을 살펴 걸릴 효율성에 대해 우려하는 경우 :

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

그래서 내가 View.findViewById (INT)와 같은 고가의 통화를 할 수 있습니다 내 응용 프로그램이 지연되지 않습니다? –

+16

'findViewById (int)'는 생각만큼 비싸지 않습니다. 참조가있는 경우에만 참조를 반환합니다. ViewHolder 기술은 다른 종류의 문제를 해결하기 위해 존재합니다 : 실제로 필요한 것보다 많은 뷰를 생성하지 마십시오 (따라서 과도한 뷰 팽창을 피할 수 있습니다. 이는 비쌉니다). – Cristian

+1

@ 크리스티안, 고마워. 'newView'와'bindView'를 사용하여 클래스가'SimpleCursorAdapter'를 확장하도록했습니다. 아래 코드를 참조하십시오. –

1

클래스의 내 구현 newViewbindView와 SimpleCursorAdapter를 확장하지만, 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() 및오버라이드 (override)하는 경우의 경우 getView()에서 추가 작업을 수행 할 필요가 없습니다. CursorAdapter은 행 재활용을 시행하기 위해 newView()bindView()에 위임하는 getView() 구현을가집니다.

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); 
     } 
    } 
} 
관련 문제