Kotlin中使用Gson解析JSON数组至Realm对象时遇类型转换异常
嘿,我来帮你排查这个问题!你遇到的com.example.android.sunshine.data.Location[] cannot be cast to java.lang.Iterable异常,核心原因是Gson解析时的类型不匹配,再加上一些异步事务和流处理的小问题,咱们一步步来修正:
1. 核心错误:Gson解析的类型不匹配
你这段代码存在类型转换的隐患:
val weatherList = gson.fromJson<List<Location>>(jsonReader , Array<Location>::class.java).toList()
这里你告诉Gson要返回List<Location>,但第二个参数传入的是Array<Location>::class.java,Gson实际会返回Location[]数组,而数组不能直接强制转换为List(虽然你调用了toList(),但前面的类型强转已经会触发异常了)。这就是导致Location[]无法转成Iterable的根源。
2. 修正方案:两种正确的解析方式
你可以任选一种方式来修复解析逻辑:
方式一:直接解析为数组,传给Realm
Realm的insertOrUpdate方法本身支持接收数组参数,所以可以直接用数组来操作:
val locationArray = gson.fromJson(jsonReader, Array<Location>::class.java) realm.insertOrUpdate(locationArray) // 直接传入数组,Realm支持这种写法
方式二:用TypeToken解析为List
如果你更习惯用List,可以借助TypeToken来指定泛型类型,让Gson直接返回List:
val type = object : TypeToken<List<Location>>() {}.type val weatherList = gson.fromJson<List<Location>>(jsonReader, type) realm.insertOrUpdate(weatherList) // List是Iterable的实现,直接传入即可
3. 其他需要调整的问题
(1)不要在异步事务里操作JsonReader
你的jsonReader.endArray()和jsonReader.close()放在了异步事务的回调里,这会导致问题:异步事务是在后台线程执行的,而你在主线程打开的输入流,可能在事务执行前就已经被系统回收,或者流操作的时机不对。应该在主线程完成流的读取和关闭,再把解析好的数据传入事务。
(2)正确管理Realm实例
你直接调用Realm.getDefaultInstance().executeTransactionAsync(...)会导致Realm实例无法被正确关闭,造成资源泄漏。可以用Kotlin的use函数来自动管理实例的生命周期。
完整修正后的代码
private fun loadStuff() { val inputStream = this.resources.openRawResource(R.raw.city_json) JsonReader(InputStreamReader(inputStream, "UTF-8")).use { jsonReader -> val gson = Gson() // 先在主线程完成JSON解析 val locationArray = gson.fromJson(jsonReader, Array<Location>::class.java) // 用use函数自动管理Realm实例,避免资源泄漏 Realm.getDefaultInstance().use { realm -> realm.executeTransactionAsync({ transactionRealm -> transactionRealm.insertOrUpdate(locationArray) }, { Log.d("TAG", "Success") }, { error -> Log.e("TAG", "Insert failed", error) }) } } }
额外检查点
- 你的
Location类已经正确添加了@RealmClass注解,并且继承了RealmObject,字段都是open的(Kotlin中Realm需要开放字段来生成代理类),这部分是没问题的。 - JSON字段和
@SerializedName的映射也完全匹配你提供的JSON示例,无需调整。
这样调整后,就能顺利解析JSON数组并插入Realm啦!
内容的提问来源于stack exchange,提问作者Lukas Anda

