0

这是 ViewHolder 模式的简单实现。我有一个包含文章的游标,我想将标题保留在行标签中。在这个阶段,我(尝试)将实际字符串和相应的 textview 保留在 row 标记中,再加上 textview 的标记中的实际字符串。

class ArticleListCursorAdapter extends SimpleCursorAdapter {
    class ViewHolder {
        String strTitle = null;
        View viewTitle = null;

        ViewHolder(View base, String strTitle) {
            this.viewTitle = base.findViewById(R.id.textTitle);
            this.strTitle = strTitle;
        }

        @Override
        public String toString() {
            return new StringBuffer()
                .append("strTtitle [").append(strTitle).append("] ")
                .append("viewTitle [").append(((TextView)viewTitle).getText()).append("] ")
                .append("viewTitle title (tag) [").append(viewTitle.getTag()).append("] ")
                .toString();
        }
    }

    public ArticleListCursorAdapter(Context context, int layout, Cursor c, String[] from,
            int[] to, int flags) {
        super(context, layout, c, from, to, flags);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View row = super.getView(position, convertView, parent);
        ViewHolder holder = null;
        // if (convertView != null)
        holder = (ViewHolder)row.getTag();

        Log.v(TAG, "getView for [" + position + "]. holder ["
                    + (holder == null ? "null holder" : holder.toString()) + "]");
        Log.v(TAG, "getView other info: rendering view title ["
                            + ((TextView)row.findViewById(R.id.textTitle)).getText()
                                    .toString() + "]");

        if (holder == null) {
            Cursor cursor = (Cursor)ArticleListCursorAdapter.this.getItem(position);
            final String strTitle = cursor.getString(cursor.getColumnIndex(ArticleData.C_TITLE));
            holder = new ViewHolder(row, strTitle);
            Log.v(TAG, "getView setup onclick for pos [" + position + "] and title ["+ strTitle + "]");
            holder.viewTitle.setTag(strTitle);
            row.setTag(holder);
        }

        return row;
    }
}

当我运行它时,我希望收到一堆:

getView for [x]. holder [strTitle [7777777] viewTitle [7777777] viewTitle title (tag)  [7777777] ]
getView other info: rendering view title [7777777]

如果文章标题是 7777777。我实际上收到的是一种奇怪的混合值

(4 items visible at a time, first page)
getView for [0]. holder [null holder]
getView other info: rendering view title [1111111]
getView setup onclick for pos [0] and title [1111111]
getView for [1]. holder [null holder]
getView other info: rendering view title [2222222]
getView setup onclick for pos [1] and title [2222222]
getView for [2]. holder [null holder]
getView other info: rendering view title [3333333]
getView setup onclick for pos [2] and title [3333333]
getView for [3]. holder [null holder]
getView other info: rendering view title [4444444]
getView setup onclick for pos [3] and title [4444444]

(page down)

getView for [4]. holder [strTitle [1111111] viewTitle [5555555] viewTitle title (tag)  [1111111] ]
getView other info: rendering view title [5555555]
getView for [5]. holder [null holder]
getView other info: rendering view title [6666666]
getView setup onclick for pos [5] and title [6666666]

one more down

getView for [6]. holder [strTitle [2222222] viewTitle [7777777] viewTitle title (tag)  [2222222] ]
getView other info: rendering view title [7777777]
getView for [7]. holder [strTitle [3333333] viewTitle [8888888] viewTitle title (tag)  [3333333] ]
getView other info: rendering view title [8888888]
getView for [8]. holder [strTitle [4444444] viewTitle [9999999] viewTitle title (tag)  [4444444] ]
getView other info: rendering view title [9999999]

(scroll up)

getView for [4]. holder [strTitle [4444444] viewTitle [5555555] viewTitle title (tag)  [4444444] ]
getView other info: rendering view title [5555555]
getView for [3]. holder [strTitle [3333333] viewTitle [4444444] viewTitle title (tag)  [3333333] ]
getView other info: rendering view title [4444444]

(scroll up again)

getView for [2]. holder [strTitle [1111111] viewTitle [3333333] viewTitle title (tag)  [1111111] ]
getView other info: rendering view title [3333333]
getView for [1]. holder [strTitle [2222222] viewTitle [2222222] viewTitle title (tag)  [2222222] ]
getView other info: rendering view title [2222222]
getView for [0]. holder [strTitle [6666666] viewTitle [1111111] viewTitle title (tag)  [6666666] ]
getView other info: rendering view title [1111111]

1/ 为什么 ViewHolder 的字符串部分不断变化?2 / viewTitle TextView 如何更改其标签内容(上面的 5555555 viewTitle 的标签中一次有 1111111,另一个是 444444)

4

1 回答 1

1

适配器回收视图以节省资源。想象一个有 1000 行的 ListView:为每一行创建一个唯一的 View 会很慢而且没有必要。所以适配器只创建了足够多的可见视图,再加上几个用于滚动;并且只是一遍又一遍地重复使用这些可回收​​的行。

您所看到的是您为每个可回收行 (0-3) 设置了一个 ViewHolder,但是当您滚动 TextViews 以反映列表数据时。这就是为什么可回收行#0 具有行#0 的strTitle值,但实际行#4 的TextView。

从评论中添加

理论上我可以为我的 1,000 行制作 1,000 个 [ViewHolders]

是的,你可以,但就像拥有 1000 个唯一行一样,这太过分了。我想提出一种更有效的方法来做你想做的事:

class ArticleListCursorAdapter extends SimpleCursorAdapter {
    private int cTitleIndex;

    public ArticleListCursorAdapter(Context context, int layout, Cursor cursor, String[] from, int[] to) {
        super(context, layout, cursor, from, to, 0);

        // Rather than check for the column index of C_TITLE every time 
        //   you use getView(), we check it only once. 
        cTitleIndex = cursor.getColumnIndex(ArticleData.C_TITLE);
    }

    // This method binds the Cursor data to your row
    @Override
    public void bindView(View view, Context context, Cursor cursor) {
        super.bindView(view, context, cursor);

        ViewHolder holder = (ViewHolder) view.getTag();
        // Create a new ViewHolder for each recyclable row
        if(holder == null) {
            holder = new ViewHolder();
            holder.viewTitle = (TextView) view.findViewById(R.id.textTitle);
            view.setTag(holder);
        }

        // Update this value each time the row is recycled, we do this in 
        //   bindView() because we already have access to the Cursor
        holder.strTitle = cursor.getString(cTitleIndex);

        // I'm not sure what this does but I kept it
        holder.viewTitle.setTag(holder.strTitle);
    }

    public class ViewHolder {
        String strTitle;
        // Changed viewTitle to a TextView to unnecessary conversions in this example
        TextView viewTitle; 
    }
}

我将所有内容从 getView() 移至 bindView()。在 CursorAdapter 中,getView() 方法调用 bindView(),这是与 Cursor 相关的所有数据发生的地方。由于您的大部分代码都与游标相关,因此将代码移到此处可以节省在 getView() 中查找游标的额外工作。您仍然可以覆盖 getView() 并调用 ViewHolder,但在这种情况下不再需要。

我还取消了对列索引的搜索,以停止那里的额外工作。(了解这并不完美,调用诸如 adapter.changeCursor() 之类的方法可能会重新排列列索引,因此您需要重新检查索引。但这是一个基本示例,我不想过度思考。 )

现在,如果您重新添加 LogCat 语句,您会注意到当您向上和向下滚动时,该行将保留匹配的 111111 和 111111 以及 444444 和 444444 对。希望能解决一些问题!

于 2012-08-08T19:56:32.667 回答