web-dev-qa-db-ja.com

ViewHolderパターンがカスタムCursorAdapterに正しく実装されていますか?

これが私のカスタム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がなかったため、わかりませんでした。問題や提案があれば、指摘していただけませんか。

28
Mohit Deshpande

CursorAdapterは、新しい行が必要になるたびにnewViewを呼び出すことはありません。すでにViewがある場合は、bindViewを呼び出すため、作成されたビューは実際に再利用されます。

とはいえ、コメントでJosephが指摘しているように、findViewByIdを繰り返し呼び出さないようにするために、ViewHolderを引き続き使用できます。

それでも効率が心配な場合は、SimpleCursorAdapterWeakHashMapのマップ)を使用する WeakReferences 実装を見てください。

WeakHashMap<View, View[]> mHolders = new WeakHashMap<View, View[]>();
46
Cristian

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

私のクラスの実装は、SimpleCursorAdapterをnewViewbindViewで拡張しますが、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
                }

            }
    }
1
Maksim Dmitriev