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

实现带复选框的Android RecyclerView时遇空列表索引越界错误

问题排查与修复

问题出在这两个关键地方:

  1. Adapter的条目数计算完全错误
    你在getItemCount()里返回的是floors.toString().length——这是把列表转成字符串后的字符长度,比如空列表转成[],长度是2,RecyclerView就会以为有2个条目要加载,但实际列表是空的,访问索引0自然就抛出越界异常了。正确的应该返回列表实际的元素数量floors.size。

  2. 更新数据后没告诉RecyclerView要刷新
    在getAllFloors()里你只是把新列表赋值给了floors,但RecyclerView根本不知道数据变了,还是按旧的条目数来渲染,这也会导致数据不同步的问题。必须在赋值后调用notifyDataSetChanged()通知刷新。

另外,Dialog Fragment里的floorList还有个小坑:每次totalFloors更新时,你都会往同一个列表里加元素,多次触发的话列表会重复。最好每次处理新数据时重新创建列表,或者先清空再添加。


修复后的代码

1. 修正Adapter

class FloorProfileDialogAdapter() : RecyclerView.Adapter<FloorProfileDialogAdapter.MyViewHolder>() {

    var floors = emptyList<String>()

    inner class MyViewHolder(val binding: ScheduleFloorDialogItemBinding) :
        RecyclerView.ViewHolder(binding.root)

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        val binding = ScheduleFloorDialogItemBinding.inflate(inflater, parent, false)
        return MyViewHolder(binding)
    }

    @SuppressLint("SetTextI18n")
    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        val currentFloor = floors[position]
        Timber.d("Current floor: $currentFloor")
        holder.binding.floorCheckBox.text = "Floor $currentFloor"
    }

    // 改这里:返回列表实际元素数量
    override fun getItemCount(): Int {
        return floors.size
    }

    fun getAllFloors(floorsReceived: List<String>) {
        Timber.d("Floors received : $floorsReceived")
        this.floors = floorsReceived
        // 加这句:通知RecyclerView刷新数据
        notifyDataSetChanged()
    }
}

2. 修正Dialog Fragment的列表重复问题

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    // 获取所有楼层列表
    createProfileViewModel.totalFloors.observe(viewLifecycleOwner) {
        Timber.d("List of floors received : $it")

        val intList = it.map(String::toInt)
        val maxFloorValue = intList.last()
        var count = 0
        // 每次都新建列表,避免重复添加
        val floorList: MutableList<String> = mutableListOf()

        try {
            while (count <= maxFloorValue) {
                floorList.add(count.toString())
                count++
            }
        } catch (e: Exception) {
            Timber.d("Exception: $e")
        }
        floorProfileDialogAdapter.getAllFloors(floorList)
        Timber.d("Floor List : $floorList")
    }
}

额外提个优化点

不要在onCreateView里直接实例化ViewModel,应该用ViewModelProvider来获取,这样ViewModel的生命周期才会和Fragment绑定,不会出现意外销毁的情况:

createProfileViewModel = ViewModelProvider(this)[CreateProfileViewModel::class.java]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 17:24:17