0

これは、ViewHolder パターンの単純な実装です。記事を含むカーソルがあり、タイトルを行タグに保持したい。この段階で、実際の文字列と対応するテキストビューを行タグに保持し、さらに実際の文字列をテキストビューのタグに保持します。

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 があり、もう 1 つは 444444 です)。

4

1 に答える 1

1

アダプタはビューをリサイクルしてリソースを節約します。1,000 行の ListView を想像してみてください。行ごとに一意の View を作成するのは時間がかかり、不要です。したがって、アダプターは、表示可能な十分な数のビューのみを作成し、さらにスクロール用にさらにいくつかのビューを作成します。これらのリサイクル可能な行を何度も再利用するだけです。

表示されているのは、リサイクル可能な行 (0 ~ 3) ごとに 1 つの ViewHolder を設定したことですが、スクロールすると TextViews が変更され、リスト データが反映されます。これが、リサイクル可能な行 #0 に行 #0 の値があるのに、実際の行 #4strTitleの 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 に答える