1

I'm retrieving a list of items from the firebase database and displaying them using RecyclerView in my android app. The problem is when I'm retrieving more than 9 items and updating some data in the 1st item (while running) as you can see in the image below the 10th item also got affected and vice-versa same with 2nd and 11th item and so on. Like when I'm adding and fixing the quantity of the 1st item , the same happens with the 10th item (the 10th item also get added with the same quantity as of 1st item).

enter image description here

enter image description here

enter image description here

MenuFragment.kt

class MenuFragment : Fragment() {

private var dishList: MutableList<DishModel> = mutableListOf()
private lateinit var myRef: DatabaseReference
lateinit var list: RecyclerView
lateinit var proceedToCartLayout: RelativeLayout
lateinit var addToCartBtn: Button
private var selectedCategory = ""

companion object {
    fun newInstance(): Fragment {
        return MenuFragment()
    }
}

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    val view = inflater.inflate(R.layout.fragment_menu, container, false)
    //retrieve id
    val bundle = this.arguments
    selectedCategory = bundle!!.getString("CATEGORY_ID")!!
    list = view.findViewById(R.id.recyclerMenu)
    myRef = FirebaseDatabase.getInstance().getReference("Category")
    proceedToCartLayout = view.findViewById(R.id.ProceedToCart)
    addToCartBtn = view.findViewById(R.id.btn_cart)
    return view
}


override fun onResume() {

    if (ConnectionManager().checkConnectivity(activity as Context)) {
        fetchMenu()

    } else {

        val alterDialog = androidx.appcompat.app.AlertDialog.Builder(activity as 
Context)
        alterDialog.setTitle("No Internet")
        alterDialog.setMessage("Connect to internet to continue")
        alterDialog.setIcon(R.drawable.nointernet)
        alterDialog.setPositiveButton("Open Settings") { _, _ ->
            val settingsIntent = Intent(Settings.ACTION_SETTINGS)//open wifi settings
            startActivity(settingsIntent)
        }

        alterDialog.setNegativeButton("Exit") { _, _ ->
            ActivityCompat.finishAffinity(activity as Activity)
        }
        alterDialog.setCancelable(false)

        alterDialog.create()
        alterDialog.show()

    }

    super.onResume()
}

private fun fetchMenu() {
    myRef.child(selectedCategory).addValueEventListener(object : ValueEventListener {
        override fun onCancelled(p0: DatabaseError) {
            Toast.makeText(context, "$p0", Toast.LENGTH_SHORT).show()
        }

        override fun onDataChange(p0: DataSnapshot) {
            if (p0.exists()) {
                dishList.clear()
                for (i in p0.children) {
                    val plan = i.getValue(DishModel::class.java)
                    dishList.add(plan!!)
                }

                val adapter = MenuAdapter(
                    context!!,
                    R.layout.menu_list_item,
                    dishList,
                    proceedToCartLayout,
                    addToCartBtn, selectedCategory
                )
                list.adapter = adapter

            }
        }

    })

}

}

MenuAdapter.kt

class MenuAdapter(
private val ctx: Context,
private val layoutResId: Int,
private val dishList:
List<DishModel>,
private val proceedToCartPassed: RelativeLayout,
private val buttonProceedToCart: Button,
private val categoryName: String
)  : RecyclerView.Adapter<MenuAdapter.MyViewHolder>() {

private lateinit var proceedToCart: RelativeLayout
private var itemSelectedCount: Int = 0
private var itemsSelectedId = arrayListOf<String>()
private var itemList = arrayListOf<DishModel>()

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MenuAdapter.MyViewHolder {
    val layoutInflater: LayoutInflater = LayoutInflater.from(ctx)
    val view: View = layoutInflater.inflate(layoutResId, null)
    return MyViewHolder(view)
}

override fun onBindViewHolder(holder: MenuAdapter.MyViewHolder, position: Int) {
    var btnClick = false
    var no = 0
    val range = 1..5

    val dish = dishList[position]
    holder.dishName.text = dish.dishName
    holder.dishPrice.text = "Rs " + dish.cost + " /-"
    Picasso.get().load(dish.image).error(R.drawable.defaultdish).into(holder.dishImage)


    holder.increaseBtn.setOnClickListener {
        if (btnClick) {
            no += 1
            if (no in range) {
                holder.quantity.text = no.toString()
                dish.qty = no
            }
        }
    }

    holder.decreaseBtn.setOnClickListener {
        if (btnClick) {
            no -= 1
            if (no in range) {
                holder.quantity.text = no.toString()
                dish.qty = no
            }
        }
    }


    proceedToCart = proceedToCartPassed

    buttonProceedToCart.setOnClickListener {
        val intent = Intent(ctx, CartActivity::class.java)
        intent.putExtra(
            "categoryId",
            categoryName
        )
        intent.putExtra(
            "selectedItemsId",
            itemsSelectedId
        )
        intent.putExtra("itemList", itemList)
        ctx.startActivity(intent)
    }

    holder.buttonAddToCart.setOnClickListener {

        if (holder.buttonAddToCart.text.toString() == "Remove") {

            itemSelectedCount--//unselected

            itemsSelectedId.remove(holder.buttonAddToCart.tag.toString())
            itemList.remove(dish)

            holder.buttonAddToCart.text = "Add"
            holder.buttonAddToCart.setBackgroundResource(R.drawable.rounded_corners)
            btnClick = false
            no = 0
            dish.qty = no
            holder.quantity.text = no.toString()


        } else {
            itemSelectedCount++//selected
            itemsSelectedId.add(holder.buttonAddToCart.tag.toString())
            itemList.add(dish)

            holder.buttonAddToCart.text = "Remove"
            holder.buttonAddToCart.setBackgroundResource(R.drawable.rounded_corners_yellow)
            btnClick = true
            no = 1
            dish.qty = no
            holder.quantity.text = no.toString()
        }

        if (itemSelectedCount > 0) {
            proceedToCart.visibility = View.VISIBLE
        } else {
            proceedToCart.visibility = View.GONE
        }

    }

    holder.buttonAddToCart.tag = dishList.indexOf(dish) + 1
}

override fun getItemCount(): Int {
    return dishList.size
}


inner class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) {

    val dishName: TextView = view.findViewById(R.id.txtDishName)
    val dishPrice: TextView = view.findViewById(R.id.txtDishPrice)
    val dishImage: ImageView = view.findViewById(R.id.dishImage)
    val buttonAddToCart: Button = view.findViewById(R.id.add_dish)
    val increaseBtn: Button = view.findViewById(R.id.increase)
    val decreaseBtn: Button = view.findViewById(R.id.decrease)
    val quantity: TextView = view.findViewById(R.id.quantity)

}

}

2 Answers2

2

Please Add holder.quantity.text = dish.qty.toString() after or before as you wish Picasso.get().load(dish.image).error(R.drawable.defaultdish).into(holder.dishImage)

Something like below.

    Picasso.get().load(dish.image).error(R.drawable.defaultdish).into(holder.dishImage)
    holder.quantity.text = dish.qty.toString()

    holder.increaseBtn.setOnClickListener

Because I can see you are not setting holder.quantity.text thinking your recyclerview item view have the default as 0 but as you know in recyclerview the views are been reused and when they. are been reused the default value is not 0 for that but the value last view which is going to be reused, which in your case is every 10th item.

The golden rule if you are working with recylerview and thinking of using default value of any view from the XML view itself, so you will be surprised when you start scrolling you will notice that that is not the case and the default value is something other than that.

  • Always set the default value in onBind so next time the view been reused it takes the default value you want
  • if you are having an if condition to update something do write it's else as well because the same caching will make you wonder why your items are behaving differently.
  • Important point, make sure your setting default value in 1st point is outside any clicklistener or any view listener you set up because we have to make sure the setter gets executed every time the onBind is getting called

I have my fair share of experience working with checkbox, edittext , radio button etc in items and giving me surprising result on scrolling hence I always make sure to follow the above points when working with recylerviews.

Dinkar Kumar
  • 2,175
  • 2
  • 12
  • 22
0

I added the below code in my adapter (override getItemViewType) and it worked !

override fun getItemViewType(position: Int): Int {
    return position
}