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

发布于 2024-10-09 19:22:38 字数 2767 浏览 0 评论 0原文

这是我的自定义 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。如果有什么问题或建议,请指出。

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

你丑哭了我 2024-10-16 19:22:38

CursorAdapter 不会在每次需要新行时调用 newView;如果它已经有一个View,它将调用bindView,因此创建的视图实际上被重用。

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

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

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

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

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

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

WeakHashMap<View, View[]> mHolders = new WeakHashMap<View, View[]>();
做个ˇ局外人 2024-10-16 19:22:38

如果您要重写 newView()bindView(),则无需在 getView() 中执行任何额外操作。 CursorAdapter 具有 getView() 的实现,该实现委托给 newView()bindView() 来强制执行行回收。

findViewById()ListView 滚动期间可能会被频繁调用,这会降低性能。即使适配器返回一个膨胀的视图进行回收,您仍然需要查找元素并更新它们。为了避免这种情况,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);
        }
    }
}

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

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

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

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);
        }
    }
}
负佳期 2024-10-16 19:22:38

我的类实现使用 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
                }

            }
    }

My implementation of a class extends SimpleCursorAdapter with newView and bindView but without the ViewHolder pattern

    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
                }

            }
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文