Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recyclerview checkbox keeping checked problem?

I am using a custom recyclerview adapter with checkbox so that user can select multiple checked items.

In the beginning I faced duplicate checkbox selection while scrolling down so I added a position array to keep checkbox selection true or false.Now duplicate checkbox selection problem is gone but while scrolling down selected checkbox are deselected.My recyclerview adpater is given below,

class IngredientsAdapter(var context: Context?,var activity: Activity, var ingredientList:ArrayList<String>, var imageID:Int):
        RecyclerView.Adapter<IngredientsAdapter.IngredientViewHolder>() {
    private var positionArray:ArrayList<Boolean> = ArrayList(ingredientList.size)
    private val selectedList=ArrayList<String>()
    init {
        for (i in ingredientList.indices) {
            positionArray.add(false)
        }
    }

    override fun onCreateViewHolder(p0: ViewGroup, p1: Int): IngredientViewHolder {
        val layoutInflater = LayoutInflater.from(p0.context)
        return (IngredientsAdapter.IngredientViewHolder(layoutInflater.inflate(R.layout.ingredient_list_row,p0,false)))
    }

    override fun getItemCount(): Int {
       return ingredientList.size
    }
    override fun onBindViewHolder(p0: IngredientViewHolder, p1: Int) {


        p0.imageView.setImageResource(imageID)
        p0.textView.text = ingredientList[p1]
        p0.checkBox.isChecked = positionArray[p1]
        val sharedPreferences= SharedPreferenceHelper(context, SystemConstants.SHARED_PREFS_CHECKDATA)
        val checked=sharedPreferences.getPrefsBooleanValue(ingredientList[p1])
        p0.checkBox.isChecked = checked
        p0.checkBox.setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener { buttonView, isChecked ->
            if(isChecked){
                positionArray[p1] = true
                selectedList.add(ingredientList[p1])
                ingredientList.get(p1)
                sharedPreferences.addPrefsBooleanVal(ingredientList[p1],true)
                Log.d("debug","selecteditem==>$selectedList")
            }else{
                positionArray[p1] = false
                selectedList.remove(ingredientList[p1])
                sharedPreferences.addPrefsBooleanVal(ingredientList[p1],false)
                Log.d("debug","selecteditem==>$selectedList")
            }
        })
    }

    class IngredientViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        var textView= itemView.txt_row!!
        var imageView= itemView.image_view!!
        var checkBox= itemView.chk_row!!
    }
}

Any suggestion is appreciated.

like image 452
Padmini S Avatar asked Apr 13 '26 15:04

Padmini S


2 Answers

OnClickListener won't work when sliding the Switch.

Since RecyclerView is recycling views, a previously attached OnCheckedChangeListener can be triggered when setting checked value for the Switch of the new item.

When binding new data to an item:

   switch.setOnCheckedChangeListener(null) // remove any existing listener from recycled view
   switch.isChecked = [true/false] // will no longer trigger any callback to listener
   switch.setOnCheckedChangeListener { btnView, isChecked ->
       // do exiting stuff
   }
like image 89
jayeffkay Avatar answered Apr 16 '26 07:04

jayeffkay


What @Bek suggested is the correct solution. You will need to use OnClickListener. Also what you commented is not wrong either, just what you used to use(ListView) is or was!

Let me break it down for you:

  1. ListView: The older version of RecyclerView.

    Wonder why the developer created another redundant component? Basically Memory Issue! ListView creates as many ItemViews as it requires whereas RecyclerView just recycles the itemView.
    For example if for a list of 100 items if we use ListView it will initially create as many ItemViews as the phone can display. Then as we scroll down it keeps creating more Views, till the 100th item(100 ItemViews in memory). But RecyclerView does this more efficiently it creates as many views it can show + 1 (Next view in list) then it keeps recycling them so we always have only As many views in screen +1 and not 100 when we reach the bottom of the list. For more details read this and this.

  2. OnCheckChangeListener: The Other problem maker!

    This listener is called whenever check changes for the checkbox, Whenever! So if i where to refresh a checkbox this listener(theoretically) will be called! Getting where am going with this? Yup when used along with RecyclerView its gonna cause an havoc in ones code. The moment recyclerView destroys or reuses an ItemView the checkbox is reset which fires the listener and causing your SharedPref to rewrite the check! I tested this by adding logs inside the listener and saw it get triggered for outer most views when it got recycled.

This is just my findings, there maybe some way or fix for this but i too would suggest using OnClickListener and write a listener to change the model in main class rather than sharedPref in adapter.

Oh! You can use ViewHolder.SetIsRecyclable(false), this would stop RecyclerView from Recycling the views and create as many views as there are items in list. But i wouldn't suggest this as the UI as well as UX will be compromised as u might find a bit lag while scrolling(Memory Issue)!

Long Story Short use OnClickListener with RecyclerView!

like image 21
frostedfire Avatar answered Apr 16 '26 07:04

frostedfire



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!