返回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

