【问题标题】:How do i prevent recycled ListView items from showing old content?如何防止回收的 ListView 项目显示旧内容?
【发布时间】:2012-04-15 09:15:48
【问题描述】:

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

@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

【问题讨论】:

    标签: android android-listview


    【解决方案1】:

    这是导致您的问题的视图回收。

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

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

    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 或类似的东西,但希望这会为你指明正确的方向。

    【讨论】:

    • 我已经解决了重复项目的问题,方法是将我的所有 ViewHeader 代码放入我之前正在做的 bindView 方法中。现在我回到以前的问题,当我单击 CheckBox 时,它在屏幕上和数据库中的状态发生了变化,但是当我将它从屏幕上滚动出来并将它带回来时,它又回到了原来的状态。有没有办法在创建状态和重绘时设置状态? (退出活动并返回显示更改)
    • 这就是我在回答中显示的代码。创建一个数组来保存项目的状态并在您的 bindView 中引用。如果您查看我的代码,您会看到我根据数组而不是直接分配按钮文本和颜色。在您进行更改时保持数组更新,并且每次加载视图时都会正确设置状态。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多