简体   繁体   中英

Checkboxes in RecyclerView is unchecked when scrolled

Suppose I check an item's checkbox , that also updates the ischecked column in the database with the respective item's id. Then I scroll down and go back to the top, then the top most item's checkbox is automatically unchecked and database is also updated. Even suppose I check two items on the top, when I scroll down the two bottom most items' checkboxes are also checked automatically. How can I resolve this problem in 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;
}

The question is bad and the first answer is also bad. RecyclerView recycles components, it is an object pool that avoids memory allocation by reusing a component and calling onBindViewHolder to actually set the data that is going to be displayed.

That means that onBindViewHolder is being called everytime a ViewHolder of your recyclerview shows up on screen doing over and over again all that busy work (setting the listeners and stuff). OnBindViewHolder should just read the data and reflect that on the holder so that it is correctly displayed.

In your case, the bug lies on the OnCheckedChangeListener you set everytime. When a ViewHolder is recycled, the checkbox is changed to reflect the dataBean array and that change is persisted on your database (inserting incorrect data as your listener is bound to an unknown position of a previously used ViewHolder). Then you set the listener and new, unpredictable behaviour is bound to happen.

You should check a bunch of tutorials on RecyclerView or give a good read on the docs/manuals of the Android SDK and try to figure out how to best layout your code.

Hope this helps :)

You have to save the state of the checkbox by using shared preferences or in Sql database . Note: shared preferences is the best solution . Search how to save checkbox state using shared preferences.

I solved it by overriding two methods in adapter class

@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemViewType(int position) {
return position;
}

Also modified the condition where it checks and unchecks items directly by retrieving from the database everytime the view is recycled instead of getting the checked state from the 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
        }

如果您在 recylerview 中的项目数量较少,并且上面的答案可以使其完美运行,您可以使用它

recycler_filter.setItemViewCacheSize(100000);

Override the method inside Adapter

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

Unique id for each item, maybe from Database. Use OnClickListener Instead of 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);
   }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM