另一个 "RecyclerView duplicating items" 个问题

Another "RecyclerView duplicating items" question

我遇到了这个问题,花了几个小时探索在这里找到的不同解决方案,但无法弄清楚。我有一个带有 RadioGroup(带有两个 RadioButton)和一个 EditText 的 RecyclerView。正如预期的那样,文本在滚动上不断重复,“原始”被删除。单选按钮也是如此。我试图在回收视图时将值保存在另一个数组备份上,但无法解决重复问题。

这是我的适配器

class ServicesCheckoutAdapter(var context: Context,
                              var servicesList: List<Service>) : RecyclerView.Adapter<ServicesCheckoutAdapter.ViewHolder>() {

    private lateinit var onRadioGroupClickListener: OnRadioGroupClickListener

    private lateinit var onTextChangedListener: OnTextChangedListener

    private lateinit var onServiceClickListener: OnServiceClickListener
    private var externalArray = mutableListOf<String>()


    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {

        val view = LayoutInflater.from(context).inflate(R.layout.services_list_item,
                parent, false)

        val viewHolder = ViewHolder(view)

        val position = viewHolder.adapterPosition

        view.setOnClickListener {

            if (onServiceClickListener != null) {
                onServiceClickListener.onServiceClick(view, servicesList[position].id, position)
            }
        }

        return viewHolder
    }

    override fun getItemId(position: Int): Long {
        return super.getItemId(position)
    }

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

    interface OnServiceClickListener {
        fun onServiceClick(view: View, serviceId: Int, position: Int)
    }

    fun setOnServiceClickListener(listener: OnServiceClickListener)
    {
        onServiceClickListener = listener
    }

    interface OnRadioGroupClickListener {
        fun onRadioGroupClick(buttonId: Int, serviceId: Int, position: Int) {}
    }

    fun setOnRadioButtonClickListener(listener: OnRadioGroupClickListener) {
        onRadioGroupClickListener = listener
    }

    interface OnTextChangedListener{
        fun onTextChanged(position: Int, text: String)
    }

    fun setOnTextChangedListener(listener: OnTextChangedListener){
        onTextChangedListener = listener
    }


    override fun onBindViewHolder(holder: ViewHolder, position: Int) {

        Log.d("recycler", "lista: ${servicesList[position].serviceSolution}")

        holder.edtSolution.removeTextChangedListener(holder.watcher)

        holder.bind(context,
                servicesList[position].id,
                servicesList[position].name,
                servicesList[position].serviceSolved,
                servicesList[position].serviceSolution,
                onRadioGroupClickListener,
                onTextChangedListener,
                position)

    }

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


    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

        var radioGroup = itemView.findViewById<RadioGroup>(R.id.radioGroupService)
        val edtSolution = itemView.findViewById<EditText>(R.id.editTextCheckoutDesc)
        var watcher: TextWatcher? = null


        fun bind(context: Context,
                 serviceId: Int,
                 serviceName: String,
                 serviceSolved: Boolean,
                 serviceSolution: String,
                 onRadioGroupClickListener: OnRadioGroupClickListener,
                 onTextChangedListener: OnTextChangedListener,
                 position: Int
        ) {

            itemView.findViewById<TextView>(R.id.serviceTitle)
                    .text = context.resources
                    .getString(R.string.service_title_comma, serviceName)

            itemView.findViewById<RadioGroup>(R.id.radioGroupService)
                    .setOnClickListener {
                        onRadioGroupClickListener
                                .onRadioGroupClick(
                                        (it as RadioGroup).checkedRadioButtonId, serviceId, adapterPosition)
                    }



            if (serviceSolved) {
                radioGroup.find<RadioButton>(R.id.radioBtnYes).isChecked = true


                radioGroup.find<RadioButton>(R.id.radioBtnNo).isChecked = false
            } else {

                radioGroup.find<RadioButton>(R.id.radioBtnYes).isChecked = false


                radioGroup.find<RadioButton>(R.id.radioBtnNo).isChecked = true
            }


            edtSolution.addTextChangedListener(object: TextWatcher{
                override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {

                }

                override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                    onTextChangedListener.onTextChanged(position, s.toString())

                }

                override fun afterTextChanged(s: Editable?) {
                }

            })

        }

    }
}

这是 activity

上的适配器初始化
serviceList = occurrence.services

        servicesAdapter = ServicesCheckoutAdapter(this, serviceList)

        recyclerViewServices.adapter = servicesAdapter
        recyclerViewServices.layoutManager = LinearLayoutManager(this)

        servicesAdapter.setOnRadioButtonClickListener(object : ServicesCheckoutAdapter.OnRadioGroupClickListener {

            override fun onRadioGroupClick(buttonId: Int, serviceId: Int, position: Int) {
                super.onRadioGroupClick(buttonId, serviceId, position)

                when (buttonId) {
                    R.id.radioBtnYes -> {
                        serviceList[position].serviceSolved = true
                        servicesAdapter.notifyDataSetChanged()
                    }

                    R.id.radioBtnNo -> {
                        serviceList[position].serviceSolved = false
                        servicesAdapter.notifyDataSetChanged()
                    }
                }
            }
        })

        servicesAdapter.setOnTextChangedListener(object : ServicesCheckoutAdapter.OnTextChangedListener{
            override fun onTextChanged(position: Int, text: String) {
                serviceList[position].serviceSolution = text
            }

        })

RecyclerView 通常不是为输入视图制作的。由于 Android 根据其 ID 保存视图的输入,因此您的 RecyclerView 有 X 个具有相同 ID 的视图,因此它们都使用相同的状态。

解决此问题的方法是在 recycle 方法中手动保存您的输入状态,然后在 bind 方法中恢复它。

所以如果你有 20 个项目,你就有 20 个状态。初始都是空的或者默认的,需要保存的时候再改。

更简单的方法是使用 LinearLayout 或类似的布局来实现您的目标,但这取决于您拥有多少项目以及将包含多少视图。

不过您仍然需要注意视图 ID 部分

我曾尝试使用 ListView,但键盘疯狂地改变了焦点。决定保留 RecyclerView,因为我的动态列表不是很大,所以我使用了

holder.setIsRecyclable(false);

在 OnBindViewHolder() 方法上,它解决了我的问题。感谢大家的帮助