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

将List<List<String>>转为MutableList时偶现崩溃问题求助

问题描述

我的应用使用List<List<String>>存储电台信息,每个子列表对应一个电台的名称、标语、流地址等内容。应用内有个「骰子」(荷兰语称dobbelsteen)功能,用于随机播放电台,搜索功能需要展示这个「骰子」项。

搜索逻辑是:检查「骰子」是否不在目标列表categorieIsSelected中,且列表非空,如果满足条件就把它添加到列表头部。但Google Play Console上报了部分崩溃,我无法复现,多数时候功能正常。

崩溃代码片段:

if (dobbelsteen !in categorieIsSelected && categorieIsSelected.isNotEmpty()) {
        
   (categorieIsSelected as MutableList<List<String>>).add(0, dobbelsteen)
    
}

错误日志:

Exception java.lang.UnsupportedOperationException:
  at java.util.AbstractList.add (AbstractList.java:153)
  at com.familiekoning.radionedplus.RadiostationsAdapter$getFilter$1.publishResults (RadiostationsAdapter.kt:725)
  at android.widget.Filter$ResultsHandler.handleMessage (Filter.java:284)
  at android.os.Handler.dispatchMessage (Handler.java:106)
  at android.os.Looper.loopOnce (Looper.java:226)
  at android.os.Looper.loop (Looper.java:313)
  at android.app.ActivityThread.main (ActivityThread.java:8741)
  at java.lang.reflect.Method.invoke
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:571)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1067)

完整搜索过滤函数代码:

override fun getFilter(): Filter = object : Filter() {

        override fun performFiltering(constraint: CharSequence): FilterResults {

            var filteredList: MutableList<List<String>> = ArrayList(ArrayList())

            if (constraint.isEmpty()) {

                filteredList = categorieWasSelected as MutableList<List<String>>

            } else {

                val filterPattern = constraint.toString().lowercase(Locale.ROOT).trim { it <= ' ' }

                if (exampleListFull != null) {

                    for (item in categorieWasSelected) {

                        if (item[0].lowercase(Locale.ROOT).contains(filterPattern)) {

                            filteredList.add(item)

                        }

                    }

                }

            }

            val results = FilterResults()

            results.values = filteredList
            results.count = filteredList.count()

            return results

        }

        override fun publishResults(constraint: CharSequence, results: FilterResults) {
            
            if (results.count > 0 && zoeken) {

                categorieIsSelected = results.values as MutableList<List<String>>

                //check of dobbelsteen erin zit bij zoekresultaat. Nee, dan toevoegen.
                if (dobbelsteen !in categorieIsSelected && categorieIsSelected.isNotEmpty()) {

                    //KT.725 geeft error is nu 726
                    (categorieIsSelected as MutableList<List<String>>).add(0, dobbelsteen)

                }

                //check of dobbelsteen als enige over is.
                if (dobbelsteen in categorieIsSelected && categorieIsSelected.size == 1) {

                    (categorieIsSelected as MutableList<List<String>>).clear()

                }

                notifyDataSetChanged()

            } else {

                categorieIsSelected = emptyList()

                notifyDataSetChanged()

            }

        }

    }
问题分析与解决方案

问题根源

崩溃的核心原因是:你强制把一个不可变的List转换成MutableList,然后调用了add或clear方法。

具体来说:

  • 在performFiltering方法中,当constraint.isEmpty()时,你直接将categorieWasSelected强转为MutableList赋值给filteredList。如果categorieWasSelected实际是不可变列表(比如通过listOf()创建、或其他方法返回的不可变视图),强转只是编译期通过,运行时实际对象还是不可变的。
  • 在publishResults中,你把results.values强转为MutableList赋值给categorieIsSelected,随后调用add或clear方法,此时如果原列表是不可变的,就会抛出UnsupportedOperationException。

另外,filteredList = categorieWasSelected as MutableList<List<String>>这种强转非常危险,你无法保证categorieWasSelected一定是可变列表。

修复方案

解决思路是确保操作的列表始终是真正的可变列表,不要依赖不安全的强转。

1. 修改performFiltering方法

override fun performFiltering(constraint: CharSequence): FilterResults {
    val filteredList = mutableListOf<List<String>>()

    if (constraint.isEmpty()) {
        // 将原列表元素复制到新的可变列表,而非直接强转
        filteredList.addAll(categorieWasSelected)
    } else {
        val filterPattern = constraint.toString().lowercase(Locale.ROOT).trim { it <= ' ' }
        if (exampleListFull != null) {
            for (item in categorieWasSelected) {
                if (item[0].lowercase(Locale.ROOT).contains(filterPattern)) {
                    filteredList.add(item)
                }
            }
        }
    }

    val results = FilterResults()
    results.values = filteredList
    results.count = filteredList.size
    return results
}

2. 简化publishResults中的强转

现在filteredList已经是真正的MutableList,无需再强转:

override fun publishResults(constraint: CharSequence, results: FilterResults) {
    if (results.count > 0 && zoeken) {
        categorieIsSelected = results.values as MutableList<List<String>>

        if (dobbelsteen !in categorieIsSelected && categorieIsSelected.isNotEmpty()) {
            categorieIsSelected.add(0, dobbelsteen)
        }

        if (dobbelsteen in categorieIsSelected && categorieIsSelected.size == 1) {
            categorieIsSelected.clear()
        }

        notifyDataSetChanged()
    } else {
        categorieIsSelected = emptyList()
        notifyDataSetChanged()
    }
}

额外优化建议

  • 避免用List<List<String>>嵌套列表存储复杂数据,建议定义数据类(比如RadioStation)来存储电台信息,代码可读性和可维护性会更高。
  • 不要依赖强制类型转换,Kotlin中尽量使用安全类型转换(as?),或提前确保列表的可变性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 10:20:42