0

I'm trying to set up a checkbox in my recycler view, but I'm facing the common problem of random checks without my control. I check one item and some more random items are being checked at the same time.

I realise this is a common question here, but the solutions I found here don't seem to work. Among many others I was trying to follow different instructions in this thread: Android RecyclerView checkbox checks itself but what seems to be the problem is that functions isSelected and setSelected can't be resolved.

My best guess is that the reason for this complication might be that my onCheckedChange action is actually interfaced from the main activity, as you can see at the bottom of the code below. Is that what complicates the code (can't avoid it)?

  public LocationRecyclerViewAdapter(List<IndividualLocation> styles,
                                     Context context, ClickListener cardClickListener, OnCheckedChangeListener checkedChangeListener, int selectedTheme) {
    this.context = context;
    this.listOfLocations = styles;
    this.selectedTheme = selectedTheme;
    this.clickListener = cardClickListener;
    this.onCheckedChangeListener = checkedChangeListener;

  }


  @Override
  public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    int singleRvCardToUse = R.layout.single_location_map_view_rv_card;
    View itemView = LayoutInflater.from(parent.getContext()).inflate(singleRvCardToUse, parent, false);
    return new ViewHolder(itemView);
  }

  public interface ClickListener {
    void onItemClick(int position);
  }

  public interface OnCheckedChangeListener {
    void onCheckboxClick(int position);
  }

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

  @Override
  public void onBindViewHolder(final ViewHolder card, int position) {

    final IndividualLocation locationCard = listOfLocations.get(position);

    card.nameTextView.setText(locationCard.getName());
    card.addressTextView.setText(locationCard.getAddress());
    card.hoursTextView.setText(locationCard.getHours());
    card.priceTextView.setText(locationCard.getPrice());
    card.categoryTextView.setText(locationCard.getCategory());
    card.cuisineTextView.setText(locationCard.getCuisine());
    card.happyHourTextView.setText(locationCard.getHappyHour());
    card.lunchDealTextView.setText(locationCard.getLunchDeal());
    card.websiteTextView.setText("WEBSITE");
    card.newPlaceTextView.setText(locationCard.getNewPlace());

    card.websiteTextView.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view) {
        String url = locationCard.getWebsite();
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setData(Uri.parse(url));
        context.startActivity(intent);
      }
    });


  static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
    TextView nameTextView;
    TextView addressTextView;
    TextView priceTextView;
    TextView hoursTextView;
    TextView categoryTextView;
    TextView cuisineTextView;
    TextView happyHourTextView;
    TextView lunchDealTextView;
    TextView newPlaceTextView;
    ConstraintLayout constraintUpperColorSection;
    CardView cardView;
    ImageView backgroundCircleImageView;
    ImageView emojiImageView;
    Button websiteTextView;
    CheckBox checkBox;

    ViewHolder(View itemView) {
      super(itemView);
      nameTextView = itemView.findViewById(R.id.location_name_tv);
      addressTextView = itemView.findViewById(R.id.location_description_tv);
      priceTextView = itemView.findViewById(R.id.location_price_tv);
      hoursTextView = itemView.findViewById(R.id.location_hours_tv);
      backgroundCircleImageView = itemView.findViewById(R.id.background_circle);
      emojiImageView = itemView.findViewById(R.id.emoji);
      constraintUpperColorSection = itemView.findViewById(R.id.constraint_upper_color);
      categoryTextView = itemView.findViewById(R.id.location_type_tv);
      cuisineTextView = itemView.findViewById(R.id.location_cuisine_tv);
      happyHourTextView = itemView.findViewById(R.id.happyhour_tv);
      lunchDealTextView = itemView.findViewById(R.id.lunchdeal_tv);
      cardView = itemView.findViewById(R.id.map_view_location_card);
      websiteTextView = itemView.findViewById(R.id.website);
      newPlaceTextView = itemView.findViewById(R.id.new_place);
      cardView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
          clickListener.onItemClick(getLayoutPosition());
        }
      });

      checkBox = itemView.findViewById(R.id.checkBox);
      checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if (isChecked) {
                    onCheckedChangeListener.onCheckboxClick(getLayoutPosition());
                }
            }});
    }
    @Override
    public void onClick(View view) {
    }


  }
}


I'm sure there is some simple solution to this, but I've been cracking my head over this for way too long now. Thanks!

4 Answers4

0

Inside your onBindViewHolder you have to set your checkbox either checked or unchecked. if true, your checkbox will be selected, else unselected, because recycler view will be recycled every time you scroll, so you need to make sure you need to tell adapter that checkbox need to be checked or unchecked at that particular position.

Mohan Sai Manthri
  • 2,808
  • 1
  • 11
  • 26
0

why are you using getLayoutPosition() for getting checkbox position

use like this holder.getAdapterPosition()

checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if (isChecked) {
                    onCheckedChangeListener.onCheckboxClick(holder.getAdapterPosition()());
                }
}});

and move this listener to your onBindViewHolder()

Priyanka
  • 3,369
  • 1
  • 10
  • 33
0

Your data model should have a boolean variable isChecked. You can also give it an default value false. Now, in your adapter function onBindViewHolder, you should set value of your checkbox ex.

card.checkBox.setChecked(locationCard.getIsChecked())

Also, in your onCheckedChanged you should update your data

locationCard.setIsChecked(isChecked)

Now each time your RecyclerView Adapter reuses and list item, it will set the value of its checkbox correctly. Hope this helps.

UrosKekovic
  • 940
  • 7
  • 10
0

First of all, you have to check the checkbox programatically, for every item. Your model should hold the data, a simple boolean could do it.

The second is the trickiest one

checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if(buttonView.isPressed()){
                if (isChecked ) {
                    onCheckedChangeListener.onCheckboxClick(holder.getAdapterPosition()());
                }}
}});

You have to check if the checkbox is actually checked, in order to avoid confusions,

barotia
  • 428
  • 4
  • 12