滚动时,取消选中RecyclerView中的复选框

时间:2018-03-31 14:17:54

标签: android checkbox android-recyclerview

假设我检查了一个项目checkbox,该项目还会使用相应项目的ID更新ischecked中的database列。然后我向下滚动并返回到顶部,然后最顶部的项目checkbox自动unchecked,数据库也会更新。甚至假设我在顶部检查两个项目,当我向下滚动最底部的两个项目时,还会自动检查checkboxes。如何在recyclerView

中解决此问题
// costume adapter class
public class DataBeanAdapter extends RecyclerView.Adapter<DataBeanAdapter.ViewHolder> implements View.OnCreateContextMenuListener {
    public List<dataBean> items;
    public int itemLayout;

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo contextMenuInfo) {
        menu.setHeaderTitle("Select The Action");
        menu.add(0, v.getId(), 0, "Call");//groupId, itemId, order, title
        menu.add(0, v.getId(), 0, "SMS");
    }

    public DataBeanAdapter(List<dataBean> items, int itemLayout) {
        this.items = items;
        this.itemLayout = itemLayout;
    }

    @Override
    public DataBeanAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext()).inflate(itemLayout, parent, false);
        return new ViewHolder(v);
    }

    @Override
    public void onBindViewHolder(final ViewHolder holder, final int position) {
        // On loading the activity recyclerview, setting properties to each list items

        // fetch id with the given item postition
        Cursor cc = myDB.getCursorByPosition(position);
        String idd = cc.getString(cc.getColumnIndex("_id"));


        String taskval = myDB.getTaskValue(idd);

        dataBean item = items.get(position); // trash
        holder.tasks.setText(taskval.trim());

        String iscGet = myDB.getischecked(idd); // false by default

        if (items.get(position).getChecked() == true) {
            holder.isc.setChecked(true);
            items.get(position).setChecked(true);
        } else if (items.get(position).getChecked() == false) {
            holder.isc.setChecked(false);
            items.get(position).setChecked(false);
        } else {
            //leave
        }


        // set inflated checkbox to null
        //   holder.isc.setOnCheckedChangeListener(null);
        //  holder.isc.setChecked(myAdapter.items.contains(items.get(position)));

        holder.isc.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
                Boolean ischecked = items.get(position).getChecked();
                if (ischecked == false) {
                    Cursor cx = myDB.getCursorByPosition(position);
                    String idx = cx.getString(cx.getColumnIndex("_id"));
                    myDB.updateCheck(idx);
                    items.get(position).setChecked(true);

                } else {
                    Cursor cx = myDB.getCursorByPosition(position);
                    String idx = cx.getString(cx.getColumnIndex("_id"));
                    myDB.updateunCheck(idx);
                    items.get(position).setChecked(false);
                }
            }
        });


        holder.tasks.setOnCreateContextMenuListener(MainActivity.this);
        holder.more.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                Cursor c = myDB.getCursorByPosition(position);
                String id = c.getString(c.getColumnIndex("_id"));

                Intent intent = new Intent(MainActivity.this, edit.class);
                intent.putExtra("taskpos", Integer.toString(position));
                intent.putExtra("taskid", id);
                startActivity(intent);

            }
        });
    }

    @Override
    public int getItemCount() {
        return items.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder {

        public TextView tasks;
        public CheckBox isc;
        public ImageView more;

        public ViewHolder(View itemView) {
            super(itemView);
            tasks = (TextView) itemView.findViewById(R.id.taskline);
            isc = (CheckBox) itemView.findViewById(R.id.cbox);
            more = (ImageView) itemView.findViewById(R.id.more);
            // https://developer.android.com/reference/android/support/v7/widget/RecyclerView.ViewHolder.html#isRecyclable()
            //  this.setIsRecyclable(false); /// prevents checkbox misbehaving


        }

    }
}

public List<dataBean> getAllData() {
    List<dataBean> list = new ArrayList<>();
    Cursor cursor = myDB.SelectData();


    while (cursor.moveToNext()) {

        int tasks = cursor.getColumnIndex("tasklist");
        int ischecked = cursor.getColumnIndex("ischecked");
        String tasksv = cursor.getString(tasks);
        String ic = cursor.getString(ischecked);
        dataBean bean = new dataBean(tasksv, Boolean.parseBoolean(ic));
        list.add(bean);

    }

    return list;
}

5 个答案:

答案 0 :(得分:0)

问题很糟糕,第一个答案也很糟糕。 RecyclerView回收组件,它是一个对象池,它通过重用组件并调用onBindViewHolder来实际设置要显示的数据来避免内存分配。

这意味着每当您的recyclerview的ViewHolder出现在屏幕上时,就会调用onBindViewHolder所有忙碌的工作(设置监听器和东西)。 OnBindViewHolder应该只读取数据并将其反映在持有者上,以便正确显示。

在您的情况下,错误在于您每次设置的OnCheckedChangeListener。回收ViewHolder时,会更改复选框以反映dataBean数组,并且该更改将保留在您的数据库中(当您的侦听器绑定到以前使用的ViewHolder的未知位置时,会插入不正确的数据)。然后设置监听器,必然会发生新的,不可预测的行为。

您应该检查一下RecyclerView上的一些教程,或者对Android SDK的文档/手册进行详细阅读,并尝试找出如何最好地布局代码。

希望这会有所帮助:)

答案 1 :(得分:0)

您必须使用共享首选项或在Sql数据库中保存复选框的状态。 注意:共享首选项是最佳解决方案。 使用共享首选项搜索如何保存复选框状态。

答案 2 :(得分:0)

我通过覆盖适配器类

中的两个方法解决了这个问题
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemViewType(int position) {
return position;
}

还修改了每次视图被回收时从数据库中检索而不是从dataBean获取检查状态时直接检查和取消选中项目的条件。

if (iscGet.equals("true")) {
            holder.isc.setChecked(true);
            items.get(position).setChecked(true);
        } else if (iscGet.equals("false")) {
            holder.isc.setChecked(false);
            items.get(position).setChecked(false);
        } else {
            //leave
        }

答案 3 :(得分:0)

如果您在recylerview中的项目数少于上述答案,则可以使用它

recycler_filter.setItemViewCacheSize(100000);

答案 4 :(得分:0)

覆盖Adapter内部的方法

@Override public long getItemId(int position) { return ItemList.get(position).getId();}

每个项目的唯一 ID,可能来自数据库。 使用 OnClickListener 而不是 OnCheckChangedListener

holder.binding.alarmChk.setOnClickListener(view -> {
    holder.binding.alarmChk.toggle();
    if (holder.binding.alarmChk.isChecked()) {
        //do something
        Log.d("OnCheckedChange", "false " + getItemId(position));
        holder.binding.alarmChk.setChecked(false);
    } else {
        //do something
        Log.d("OnCheckedChange", "false " + getItemId(position));
        holder.binding.alarmChk.setChecked(true);
   }