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
相关产品推荐
相关产品推荐

