java 在自定义 CursorAdapter 中正确实现了 ViewHolder 模式?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4567969/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 07:00:19  来源:igfitidea点击:

ViewHolder pattern correctly implemented in custom CursorAdapter?

javaandroidadapter

提问by Mohit Deshpande

Here is my custom 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;
    }

}

Does this fall into the constraints of the ViewHolder pattern? I wasn't sure because this was a CursorAdapter, where there was no getView. If there are any problems or suggestions, could you please point them out.

这是否属于 ViewHolder 模式的约束?我不确定,因为这是一个 CursorAdapter,没有getView. 如果有任何问题或建议,请您指出。

回答by Cristian

CursorAdapterwon't call the newVieweach time it needs a new row; if it already has a View, it will call the bindView, so the created view is actually reused.

CursorAdapternewView每次需要新行时都不会调用;如果它已经有一个View,它会调用bindView,所以创建的视图实际上会被重用。

That said, as pointed out by Josephin the comments, you can still use ViewHolder in order to avoid calling findViewByIdrepeatedly.

也就是说,正如约瑟夫在评论中指出的那样,您仍然可以使用 ViewHolder 以避免findViewById重复调用。

If you are still concerned about efficiency then take a look at the SimpleCursorAdapterimplementation, which uses a WeakHashMap(a map of WeakReferences):

如果您仍然关心效率,请查看SimpleCursorAdapter使用WeakHashMap(的映射WeakReferences)的实现:

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

回答by Yogesh Umesh Vaity

If you are overriding newView()and bindView(), you don't need to do anything extra in getView(). CursorAdapterhas an implementation of getView()that delegates to newView()and bindView()to enforce the row recycling.

如果您覆盖newView()and bindView(),则无需在getView(). CursorAdapter具有getView()委托newView()bindView()强制执行行回收的实现。

findViewById()maybe called frequently during the scrolling of ListView, which can slow down performance. Even when the Adapterreturns an inflated view for recycling, you still need to look up the elements and update them. To avoid this, ViewHolderpattern is useful.

findViewById()可能会在 滚动期间频繁调用ListView,这会降低性能。即使Adapter返回一个膨胀的视图以供回收,您仍然需要查找元素并更新它们。为了避免这种情况,ViewHolder模式很有用。

Here's an example of ViewHolderpattern implemented for a weather app:

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

回答by Maksim Dmitriev

My implementation of a class extends SimpleCursorAdapter with newViewand bindViewbut without the ViewHolderpattern

我的一个类的实现扩展了 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
                }

            }
    }