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

Kotlin遍历RecyclerView获取EditText输入值异常问题求解

问题根因

你遇到的返回子项数量不足、偶发获取失败是RecyclerView的复用机制导致的:

  • RecyclerView只会在内存中保留屏幕可见区域+少量预加载的子View,getChildCount()返回的就是这部分可见/预加载的子项数量,而非你设置的总数据量
  • 滚出屏幕的子项会被回收复用,此时调用findViewHolderForAdapterPosition()获取滚出屏幕位置的ViewHolder会返回null,自然拿不到输入内容
  • 直接通过遍历RecyclerView子View拿输入的方案本身就不符合RecyclerView的设计规范,可靠性极低。

解决方案

最佳实现是在Adapter内部实时存储用户的输入内容,不要等到提交时才临时从View读取,具体修改步骤如下:

步骤1:修改AcrosticAdapter

在Adapter中新增输入存储列表、输入监听逻辑、对外暴露获取所有输入的方法:

class AcrosticAdapter(
    // 保留你的原有初始化参数,比如目标词对应的字母列表
    private val letterList: List<Char>
) : RecyclerView.Adapter<AcrosticAdapter.ViewHolder>() {

    // 新增:存储每个位置的输入内容,初始化时和总数据量保持一致,填充空字符串
    val inputList: MutableList<String> = MutableList(letterList.size) { "" }

    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val imgLetter: ImageView = itemView.findViewById(R.id.imgLetter)
        val txtWord: EditText = itemView.findViewById(R.id.txtWord)
        // 存储当前绑定的TextWatcher,避免复用导致的输入错乱
        var textWatcher: TextWatcher? = null
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        // 先移除之前绑定的TextWatcher,避免复用导致的输入串位
        holder.textWatcher?.let { holder.txtWord.removeTextChangedListener(it) }
        
        // 原有绑定逻辑:设置字母图片、hint等
        // holder.imgLetter.setImageResource(对应字母的图片资源ID)
        holder.txtWord.hint = letterList[position].toString()
        // 回显已存储的输入内容,避免滚动时输入丢失
        holder.txtWord.setText(inputList[position])

        // 新增TextWatcher实时存储用户输入
        val watcher = object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
            override fun afterTextChanged(s: Editable?) {
                inputList[position] = s?.toString() ?: ""
            }
        }
        holder.txtWord.addTextChangedListener(watcher)
        holder.textWatcher = watcher
    }

    override fun getItemCount(): Int = letterList.size

    // 对外暴露方法,获取所有输入内容
    fun getAllInputs(): List<String> = inputList.toList()
}

步骤2:修改saveTask函数

不需要再遍历RecyclerView的子View,直接调用Adapter暴露的方法即可拿到所有位置的输入:

private fun saveTask() {
    val allInputs = (acrosticRecycler.adapter as AcrosticAdapter).getAllInputs()
    allInputs.forEachIndexed { index, word ->
        Log.d(HWG.TAG, "第${index+1}个输入:$word")
    }
    // 后续自定义处理逻辑
}

可选补充方案(适用于目标词长度始终较小的场景)

如果你的目标词长度最多不超过10个,也可以直接放弃RecyclerView,改用LinearLayout动态添加子项,就不会存在复用问题,直接遍历LinearLayout的子View就能拿到所有输入。这种方案在数据量大时性能不如RecyclerView,可以根据你的业务场景自行选择。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 04:51:04