You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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
    }
}

关键修改说明

  1. 同步更新数据源:每次加减操作时,先修改quantityMap中的数值,再更新UI,确保onBindViewHolder复用ViewHolder时能获取到最新值。
  2. 优化RequestQueue:用lazy初始化全局RequestQueue,避免重复创建资源浪费。
  3. 修复减号逻辑:当数量为1时不再继续减少,防止出现负数。
  4. 空值处理:对toIntOrNull()的结果做默认值兜底,避免空指针异常。

另外,如果你不想用quantityMap,可以直接在TodaydealItem实体类中添加quantity字段,修改数量后调用notifyItemChanged(position)通知RecyclerView更新UI,这种方式更符合数据驱动的设计思想,也能避免之前的乱跳问题。

内容的提问来源于stack exchange,提问作者xoxoxo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 15:43:21