Android 行标记,ViewHolder图案

Android 行标记,ViewHolder图案,android,row,adapter,Android,Row,Adapter,这是ViewHolder模式的一个简单实现。我有一个包含文章的游标,我想将标题保留在行标记中。在此阶段,我(尝试)将实际字符串和相应的textview保留在行标记中,并将实际字符串保留在textview的标记中 class ArticleListCursorAdapter extends SimpleCursorAdapter { class ViewHolder { String strTitle = null; View viewTitle = nul

这是ViewHolder模式的一个简单实现。我有一个包含文章的游标,我想将标题保留在行标记中。在此阶段,我(尝试)将实际字符串和相应的textview保留在行标记中,并将实际字符串保留在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]
如果文章标题是777。我实际上收到的是一种奇怪的价值观组合

(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)

适配器回收视图以节省资源。设想一个有1000行的ListView:为每行创建一个唯一的视图会很慢,而且没有必要。因此适配器只创建足够的可见视图,再加上一些用于滚动的视图;并且简单地重复使用这些可回收的行

您看到的是,您已经为每个可循环行(0-3)设置了一个ViewHolder,但是当您滚动文本视图时,它会改变以反映列表数据。这就是为什么可回收行#0具有行#0的
strTitle
值,而实际行#4具有文本视图

从评论中添加内容

理论上,我可以为我的1000行制作1000个[viewholder]

是的,您可以,但就像有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()。在游标适配器中,getView()方法调用bindView(),这是与游标相关的所有数据发生的地方。由于大多数代码都与光标相关,因此在此处移动代码可以节省在getView()中查找光标的额外工作。您仍然可以重写getView()并调用ViewHolder,但在这种情况下不再需要它

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


现在,如果您将LogCat语句添加回,您会注意到,当您上下滚动时,该行将保留匹配111111和111111以及444444和444444对。希望能澄清一些事情

我对您所做工作的基本原则感到困惑,为什么不在您的
数组中从[]
传递
ArticleData.C_TITLE
R.id.textTitle
?这不是SimpleCorsOrAdapter已经做过的,将列绑定到视图吗?我想做的是处理一些小部件上的点击。所以我重写了适配器,实现了ViewHandler模式。在getView中,我使用OnClick方法中的strTitle创建一个OnClick侦听器。但情况一直在变化。因此,我试图了解整个ViewHandler/getTag概念是如何工作的。我想当我通过一排标签中的某个东西时,我会在那里找到它。这表明我在我的意图中遗漏了什么,这是一种预期的行为吗?我的意思是,保存“55555”字符串的TextView应该附带任意标记???嗯。所以你是说我没有每行一个ViewHandler(理论上我可以为我的1000行制作1000个),而是每可见行一个(在本例中为4个)。谢谢山姆的澄清。