28 Stimmen

ViewHolder-Muster korrekt in benutzerdefinierten CursorAdapter implementiert?

Hier ist mein benutzerdefinierter 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;
    }

}

Fällt dies unter die Beschränkungen des ViewHolder-Musters? Ich war mir nicht sicher, weil es sich um einen CursorAdapter handelt, bei dem es keine getView . Falls es Probleme oder Vorschläge gibt, können Sie uns diese bitte mitteilen.

45voto

Cristian Punkte 195886

CursorAdapter ruft nicht die newView jedes Mal, wenn es eine neue Zeile benötigt; wenn es bereits eine View auf, ruft es die bindView , so dass die erstellte Ansicht tatsächlich wiederverwendet wird.

Diesbezüglich wird darauf hingewiesen, dass, wie von Joseph in den Kommentaren, können Sie trotzdem ViewHolder verwenden, um den Aufruf von findViewById wiederholt.

Wenn Sie immer noch über die Effizienz besorgt sind, dann werfen Sie einen Blick auf die SimpleCursorAdapter Implementierung, die eine WeakHashMap (eine Karte von WeakReferences ):

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

8voto

Yogesh Umesh Vaity Punkte 26562

Wenn Sie die folgenden Punkte überschreiben newView() y bindView() brauchen Sie nichts weiter zu tun in getView() . CursorAdapter hat eine Implementierung von getView() die delegiert an newView() y bindView() um das Zeilenrecycling durchzusetzen.

findViewById() wird möglicherweise häufig während des Scrollens von ListView was die Leistung beeinträchtigen kann. Selbst wenn die Adapter eine aufgeblähte Ansicht zur Wiederverwendung zurückgibt, müssen Sie die Elemente immer noch nachschlagen und aktualisieren. Um dies zu vermeiden, ViewHolder Muster nützlich ist.

Hier ist ein Beispiel für ViewHolder Muster für eine Wetter-App implementiert:

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

1voto

Maksim Dmitriev Punkte 5627

Meine Implementierung einer Klasse erweitert SimpleCursorAdapter mit newView y bindView aber ohne die ViewHolder Muster

    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
                }

            }
    }

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X