Android电商App RecyclerView商品数量计数器滚动重置问题求助
问题:RecyclerView商品计数器滚动后重置的解决方法
问题描述
我正在开发一款Android电商App,使用RecyclerView展示商品,每个商品卡片中设有用于增减购买数量的计数器。当前遇到的问题是:当我通过计数器增加商品数量后,滚动RecyclerView时,数量会自动重置为初始值。曾尝试不使用HashMap,这种方式能保留数据,但会出现多个商品的数量在未操作的情况下莫名变化的问题。
原Adapter代码
class testadapter( private val context: Context, private val todaylist: ArrayList<TodaydealItem> ) : RecyclerView.Adapter<testadapter.MyView>() { class MyView(itemView: View) : RecyclerView.ViewHolder(itemView) { var prodid: TextView = itemView.findViewById(R.id.prodid) var qty: EditText = itemView.findViewById(R.id.qty) var sub: Button = itemView.findViewById(R.id.sub) var add: Button = itemView.findViewById(R.id.add) } private val quantityMap: HashMap<String, Int> = HashMap() override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyView { val itemView = LayoutInflater.from(parent.context) .inflate(R.layout.testlayout, parent, false) return MyView(itemView) } override fun onBindViewHolder(holder: MyView, position: Int) { val currentItem = todaylist[position] val resources = context.resources val producturl = resources.getString(R.string.domain_url) + "api/v2/products/" + currentItem.id holder.prodid.text = currentItem.id val quantity = quantityMap[currentItem.id] ?: 1 holder.qty.setText(quantity.toString()) holder.add.setOnClickListener { val currcount = holder.qty.text.toString() val currcountasnum: Int? = currcount.toIntOrNull() val stringRequest = StringRequest( Request.Method.GET, producturl, { s: String? -> try { val jsonObject = JSONObject(s.toString()) val dataArray = jsonObject.getJSONArray("data") if (dataArray.length() > 0) { val dataObject = dataArray.getJSONObject(0) if (dataObject.has("current_stock")) { val currentStock = dataObject.getInt("current_stock") if (currcountasnum!! < currentStock) { holder.qty.setText((currcountasnum + 1).toString()) } else { Toast.makeText( context, "Maximum Stock Reached!", Toast.LENGTH_LONG ).show() } } } } catch (e: JSONException) { e.printStackTrace() } } ) { volleyError: VolleyError -> Toast.makeText(context, volleyError.message, Toast.LENGTH_LONG).show() } val requestQueue = Volley.newRequestQueue(context) requestQueue.add(stringRequest) } holder.sub.setOnClickListener { val currcount = holder.qty.text.toString() val currcountasnum: Int? = currcount.toIntOrNull() if (currcountasnum!! > 1) { holder.qty.setText((currcountasnum - 1).toString()) } else { holder.qty.setText((currcountasnum - 1).toString()) } } } override fun getItemCount(): Int { return todaylist.size } }
解决方案
核心问题是修改UI数值后未同步更新quantityMap,RecyclerView复用ViewHolder时会从quantityMap取初始值重置UI。同时减号按钮逻辑存在错误,以下是修正后的代码:
class testadapter( private val context: Context, private val todaylist: ArrayList<TodaydealItem> ) : RecyclerView.Adapter<testadapter.MyView>() { class MyView(itemView: View) : RecyclerView.ViewHolder(itemView) { var prodid: TextView = itemView.findViewById(R.id.prodid) var qty: EditText = itemView.findViewById(R.id.qty) var sub: Button = itemView.findViewById(R.id.sub) var add: Button = itemView.findViewById(R.id.add) } private val quantityMap: HashMap<String, Int> = HashMap() // 初始化RequestQueue,避免每次请求创建新实例 private val requestQueue by lazy { Volley.newRequestQueue(context) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyView { val itemView = LayoutInflater.from(parent.context) .inflate(R.layout.testlayout, parent, false) return MyView(itemView) } override fun onBindViewHolder(holder: MyView, position: Int) { val currentItem = todaylist[position] val prodId = currentItem.id val resources = context.resources val producturl = resources.getString(R.string.domain_url) + "api/v2/products/" + prodId holder.prodid.text = prodId // 从Map中取当前数量,默认1 val currentQty = quantityMap.getOrDefault(prodId, 1) holder.qty.setText(currentQty.toString()) holder.add.setOnClickListener { val currcountStr = holder.qty.text.toString() val currcountasnum = currcountStr.toIntOrNull() ?: currentQty val stringRequest = StringRequest( Request.Method.GET, producturl, { s: String? -> try { val jsonObject = JSONObject(s.toString()) val dataArray = jsonObject.getJSONArray("data") if (dataArray.length() > 0) { val dataObject = dataArray.getJSONObject(0) if (dataObject.has("current_stock")) { val currentStock = dataObject.getInt("current_stock") if (currcountasnum < currentStock) { val newQty = currcountasnum + 1 // 先更新数据源 quantityMap[prodId] = newQty // 再更新UI holder.qty.setText(newQty.toString()) } else { Toast.makeText( context, "Maximum Stock Reached!", Toast.LENGTH_LONG ).show() } } } } catch (e: JSONException) { e.printStackTrace() } } ) { volleyError: VolleyError -> Toast.makeText(context, volleyError.message ?: "Request failed", Toast.LENGTH_LONG).show() } requestQueue.add(stringRequest) } holder.sub.setOnClickListener { val currcountStr = holder.qty.text.toString() val currcountasnum = currcountStr.toIntOrNull() ?: currentQty if (currcountasnum > 1) { val newQty = currcountasnum - 1 // 先更新数据源 quantityMap[prodId] = newQty // 再更新UI holder.qty.setText(newQty.toString()) } else { // 数量不能小于1,保持当前值 holder.qty.setText("1") } } } override fun getItemCount(): Int { return todaylist.size } }
关键修改说明
- 同步更新数据源:每次加减操作时,先修改
quantityMap中的数值,再更新UI,确保onBindViewHolder复用ViewHolder时能获取到最新值。 - 优化RequestQueue:用
lazy初始化全局RequestQueue,避免重复创建资源浪费。 - 修复减号逻辑:当数量为1时不再继续减少,防止出现负数。
- 空值处理:对
toIntOrNull()的结果做默认值兜底,避免空指针异常。
另外,如果你不想用quantityMap,可以直接在TodaydealItem实体类中添加quantity字段,修改数量后调用notifyItemChanged(position)通知RecyclerView更新UI,这种方式更符合数据驱动的设计思想,也能避免之前的乱跳问题。
内容的提问来源于stack exchange,提问作者xoxoxo
相关产品推荐
相关产品推荐

