android - 如何防止回收的 ListView 项目显示旧内容?

标签 android android-listview

我正在处理一个 ListView,它使用自定义 ResourceCursorAdapter 来显示一个 TextView 和一个 CheckBox。 TextView 和 CheckBox 从 Cursor 获取它们的状态。我遇到了一些问题,最近的问题是当我滚动时,一些行有来自旧 TextViews 的文本,并且一些 CheckBoxes 在不应该被选中时被选中。我添加了一个日志行以查看发生了什么,这让我更加困惑。

@Override
public void bindView(View v, Context ctx, Cursor c) {
    ViewHolder holder = (ViewHolder)v.getTag();

holder.tv.setText(holder.tvText);           
holder.cb.setChecked(holder.checked);
Log.d(TAG, "in bindView, rowId:" + holder.rowId + " Scripture:" + holder.tvText);   
}

.

@Override
public View newView(Context ctx, Cursor c, ViewGroup vg){       

    View v = li.inflate(layout, vg, false);
    ViewHolder holder;

    holder = new ViewHolder();
    holder.tv = (TextView)v.findViewById(to[0]);
    holder.tvText = c.getString(c.getColumnIndex(from[0]));
    holder.cb = (CheckBox)v.findViewById(to[1]);
    holder.rowId = c.getLong(c.getColumnIndex(from[2]));
    holder.checked = (c.getString(c.getColumnIndexOrThrow(from[1])).equals("n")) ?
            false : true;
    holder.cb.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            View rowView = ((View)v.getParent());
            ViewHolder holder = (ViewHolder)rowView.getTag();

            holder.checked = (holder.checked == false) ? true : false;

            smDb.setMemorized(holder.rowId);
            rowView.setTag(holder);
            Log.d(TAG, "check box clicked: " + holder.rowId);
        }});
    Log.d(TAG, "in newView, rowId:" + holder.rowId);
    v.setTag(holder);


    return v;       
}

.

static class ViewHolder {
    TextView tv;
    String tvText;
    CheckBox cb;
    boolean checked;
    Long rowId;
}

日志输出

in newView, rowId:26
in bindView, rowId:26 Scripture:Matthew 5:14-6
in bindView, rowId:26 Scripture:Matthew 5:14-6
in bindView, rowId:26 Scripture:Matthew 5:14-6
in bindView, rowId:26 Scripture:Matthew 5:14-6
in bindView, rowId:26 Scripture:Matthew 5:14-6
in bindView, rowId:26 Scripture:Matthew 5:14-6
in bindView, rowId:26 Scripture:Matthew 5:14-6
in bindView, rowId:26 Scripture:Matthew 5:14-6
in bindView, rowId:26 Scripture:Matthew 5:14-6
in bindView, rowId:26 Scripture:Matthew 5:14-6
in bindView, rowId:26 Scripture:Matthew 5:14-6
in newView, rowId:27
in bindView, rowId:27 Scripture:Matthew 6:24
in newView, rowId:28
in bindView, rowId:28 Scripture:Matthew 16:15-9
in newView, rowId:29
in bindView, rowId:29 Scripture:Matthew 25:40
in newView, rowId:30
in bindView, rowId:30 Scripture:Luke 24:36-9
in newView, rowId:31
in bindView, rowId:31 Scripture:John 3:5
in newView, rowId:32
in bindView, rowId:32 Scripture:John 7:17
in newView, rowId:33
in bindView, rowId:33 Scripture:John 10:16
in newView, rowId:34
in bindView, rowId:34 Scripture:John 14:15
in newView, rowId:26
in bindView, rowId:26 Scripture:Matthew 5:14-6
in bindView, rowId:26 Scripture:Matthew 5:14-6
in bindView, rowId:26 Scripture:Matthew 5:14-6
in bindView, rowId:26 Scripture:Matthew 5:14-6
in bindView, rowId:26 Scripture:Matthew 5:14-6
in bindView, rowId:26 Scripture:Matthew 5:14-6
in bindView, rowId:26 Scripture:Matthew 5:14-6
in bindView, rowId:26 Scripture:Matthew 5:14-6
in bindView, rowId:26 Scripture:Matthew 5:14-6
in bindView, rowId:26 Scripture:Matthew 5:14-6

最佳答案

导致您出现问题的是 View 回收。

我不确定这是最流畅的处理方式,但我就是这样做的。我创建了一个数组来保存我的按钮状态信息,然后在我的 getView 方法中使用它来确保即使元素离开屏幕也能保持状态。

示例来 self 的一个项目,其中我有一个列表适配器,每行都有按钮,可以有多种状态(文本和颜色):

public class ButtonCursorAdapter extends SimpleCursorAdapter {
    private Cursor c;                       // Passed in cursor
    private Context context;
    private Activity activity;
    public static String[] atdState;       // String array to hold button state
    public static String[] atdRow;         // Matching string array to hold db rowId

    public ButtonCursorAdapter(Context context, int layout, Cursor c,
                    String[] from, int[] to) {
            super(context, layout, c, from, to);
            this.c = c;
            this.context = context;
            this.activity = (Activity) context;
            atdState = new String[c.getCount()];  // initialize button state array
            atdRow = new String[c.getCount()];    // initialize db rowId array
            c.moveToFirst();
            int i = 0;
            while (c.isAfterLast() == false) {
                    if (c.getString(3) == null) {  // if state is null, set to " "
                            atdState[i] = " ";
                    } else {
                            atdState[i] = c.getString(3);  // set state to state saved in db
                    }
                    atdRow[i] = c.getString(0);     // set the rowId from the db
                    i++;
                    c.moveToNext();
            }
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
            if (convertView == null)
                    convertView = View.inflate(context,
                                    R.layout.listlayoutdoublebutton, null);
            final int pos = position;
            View row = convertView;
            c.moveToPosition(position);
            TextView first = (TextView) convertView.findViewById(R.id.ListItem1);
            TextView last = (TextView) convertView.findViewById(R.id.ListItem2);
            Button atdButton = (Button) convertView.findViewById(R.id.attendbutton);
            first.setText(c.getString(1));
            last.setText(c.getString(2));
            atdButton.setText(atdState[position]);  // set the button state
            if (atdState[position].equals("P")) {   // colorize the button depending on state
                    atdButton.getBackground().setColorFilter(0xFF00FF00,
                                    PorterDuff.Mode.MULTIPLY);
            } else if (atdState[position].equals("T")) {
                    atdButton.getBackground().setColorFilter(0xFFFFFF00,
                                    PorterDuff.Mode.MULTIPLY);
            } else if (atdState[position].equals("E")) {
                    atdButton.getBackground().setColorFilter(0xFFFF6600,
                                    PorterDuff.Mode.MULTIPLY);
            } else if (atdState[position].equals("U")) {
                    atdButton.getBackground().setColorFilter(0xFFFF0000,
                                    PorterDuff.Mode.MULTIPLY);
            } else {
                    atdButton.getBackground().clearColorFilter();
            }
            atdButton.setFocusable(true);
            atdButton.setClickable(true);

            atdButton.setOnClickListener(new OnClickListener() {
                    @Override
                    public void onClick(View view) {
                            Button atdButton = (Button) view
                                            .findViewById(R.id.attendbutton);
                            String test = atdButton.getText().toString();
                            if (test.equals(" ")) {
                                    atdButton.setText("P");
                                    atdState[pos] = "P";
                                    atdButton.getBackground().setColorFilter(0xFF00FF00,
                                                    PorterDuff.Mode.MULTIPLY);
                            } else if (test.equals("P")) {
                                    atdButton.setText("T");
                                    atdState[pos] = "T";
                                    atdButton.getBackground().setColorFilter(0xFFFFFF00,
                                                    PorterDuff.Mode.MULTIPLY);
                            } else if (test.equals("T")) {
                                    atdButton.setText("E");
                                    atdState[pos] = "E";
                                    atdButton.getBackground().setColorFilter(0xFFFF6600,
                                                    PorterDuff.Mode.MULTIPLY);
                            } else if (test.equals("E")) {
                                    atdButton.setText("U");
                                    atdState[pos] = "U";
                                    atdButton.getBackground().setColorFilter(0xFFFF0000,
                                                    PorterDuff.Mode.MULTIPLY);
                            } else if (test.equals("U")) {
                                    atdButton.setText("P");
                                    atdState[pos] = "P";
                                    atdButton.getBackground().setColorFilter(0xFF00FF00,
                                                    PorterDuff.Mode.MULTIPLY);
                            }
                    }
            });
            return (row);
    }

在我使用 setText 并为我的按钮着色的地方,您可能想要 setChecked 或类似的东西,但希望这会为您指明正确的方向。

关于android - 如何防止回收的 ListView 项目显示旧内容?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10158707/

相关文章:

Android - 按下后退按钮时停止 AsyncTask 并返回到上一个 Activity

java - AsyncTask 中 android 中的互联网连接检测

android - 在代码下方运行时,GC 因 GC_CONCURRENT 而发疯

android - 如何使状态栏透明?

android - SupportMapFragment vs MapFragment 性能方面

java - 返回空指针的处理程序

带有自定义适配器的 Android ListView 多个数组

android - Android 中的 ListView 分页

java - 快速滚动大字母缩略图预览未出现

java - android开发人员警报对话框+ ListView 功能