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

返回Fragment时触发ArrayIndexOutOfBoundsException问题排查与修复

嘿,这个问题我太熟悉了!之前做项目的时候也踩过一模一样的坑,我来给你拆解下原因和解决办法~

问题根源

你现在的代码是依赖Chip的checkedId来计算数组索引的(checkedId - 1),但这里有个致命的问题:当Fragment导航返回时,视图会被销毁重建,系统会给新创建的Chip分配全新的id,不再是第一次加载时的连续值。

比如你第一次加载时,第二个Chip的id是2,所以2-1=1对应数组的第二个元素;但导航返回后,系统给这个Chip分配的id变成了9,9-1=8,而你的数组长度只有7,自然就触发了ArrayIndexOutOfBoundsException。

修复方案

这里给你三个靠谱的解决办法,你可以根据自己的场景选:

方案1:给Chip设置固定id(最稳妥)

直接在布局文件里给每个Chip手动指定和数组索引对应的id,比如:

<com.google.android.material.chip.ChipGroup
    android:id="@+id/myChips"
    ...>

    <com.google.android.material.chip.Chip
        android:id="@+id/chip_food_0"
        android:text="@string/food_0"
        ... />

    <com.google.android.material.chip.Chip
        android:id="@+id/chip_food_1"
        android:text="@string/food_1"
        ... />

    <!-- 依次给所有Chip设置对应索引的id -->
</com.google.android.material.chip.ChipGroup>

然后在代码里通过id映射到数组索引:

myChips.setOnCheckedChangeListener { group, checkedId ->
    val index = when(checkedId) {
        R.id.chip_food_0 -> 0
        R.id.chip_food_1 -> 1
        // 把所有Chip的id和索引对应上
        else -> 0 // 默认选中第一个元素
    }
    chipFromArray = foodArray[index]
}

不管视图怎么重建,Chip的id都是固定的,索引映射绝不会出错。

方案2:用Tag绑定数组索引(更灵活)

如果不想硬写一堆id判断,可以在初始化Chip的时候,把数组索引存到Chip的tag属性里:

// 如果你是动态创建Chip:
foodArray.forEachIndexed { index, foodName ->
    val chip = Chip(requireContext()).apply {
        text = foodName
        tag = index // 把当前数组索引存到tag
        isCheckable = true
    }
    myChips.addView(chip)
}

// 如果是布局里写死的Chip,就在onViewCreated里手动设置tag:
myChips.children.forEachIndexed { index, view ->
    if (view is Chip) {
        view.tag = index
    }
}

然后在监听回调里直接取tag作为索引:

myChips.setOnCheckedChangeListener { group, checkedId ->
    val selectedChip = group.findViewById<Chip>(checkedId)
    // 从tag里取出索引,直接用
    val index = selectedChip.tag as Int
    chipFromArray = foodArray[index]
}

这种方式不用关心系统分配的id,只要Chip的顺序和数组一致就没问题,适合数组长度可能变化的场景。

方案3:用checkedChipPosition获取位置(最简单)

ChipGroup自带checkedChipPosition属性,它返回的是选中Chip在组内的位置索引,这个索引和你的数组索引是一一对应的(前提是Chip的顺序和数组顺序完全一致):

myChips.setOnCheckedChangeListener { group, checkedId ->
    val position = group.checkedChipPosition
    // 如果没有选中的Chip,默认取第一个元素
    val index = if (position != -1) position else 0
    chipFromArray = foodArray[index]
}

这个方法代码最少,但要注意必须保证Chip在ChipGroup里的顺序和foodArray的顺序完全一致,如果布局里调整了Chip的顺序,就会取错值。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 18:27:46