Kotlin中如何在SharedPreferences存储ArrayList对象及报错解决
问题回顾
你在用Kotlin开发Android应用时,尝试通过Gson将ArrayList<ProductQuantityData>序列化后存入SharedPreferences,但初始实现的读取方法触发了JsonSyntaxException,错误提示为Expected BEGIN_OBJECT but was STRING。不过你已经通过修改读取方法解决了问题,我来帮你拆解下问题根源,再分享几个可以优化的点。
初始代码的问题所在
你最初的读取方法里,把Gson().toJson(ArrayList<ProductQuantityData>())作为getString的默认值——也就是把空ArrayList转成的JSON字符串([])当默认值。这个做法存在两个隐患:
- 如果SharedPreferences里对应key的存储内容不是合法的JSON数组(比如之前误存了普通字符串,或者第一次初始化时出现异常),Gson去解析这个无效内容时,就会因为格式不匹配抛出崩溃。
- 其实完全没必要用空数组的JSON当默认值,反而增加了出错的概率。
修正后代码的核心优化
你修改后的读取方法完美规避了这个问题,关键改动有两个:
- 把
getString的默认值改成了空字符串"",而非空数组的JSON - 先判断读取到的字符串是否为空,空的话直接返回空ArrayList;非空时再用Gson解析,从根源避免了解析无效内容的情况
这里再清晰贴出你的修正后代码:
private val sharedPreferences: SharedPreferences = context.getSharedPreferences(context.packageName, Context.MODE_PRIVATE) fun getProductInArrayListWithQuantities(key: String): ArrayList<ProductQuantityData> { var prodQte: ArrayList<ProductQuantityData> val json = sharedPreferences.getString(key, "") prodQte = if (json!!.isEmpty()) { ArrayList() } else { val type = object : TypeToken<ArrayList<ProductQuantityData>>() {}.type Gson().fromJson<ArrayList<ProductQuantityData>>(json, type) } return prodQte } fun setProductInArrayListWithQuantities(dataArrayList: ArrayList<ProductQuantityData>, key: String) { val jsonString = Gson().toJson(dataArrayList) sharedPreferences.edit().putString(key, jsonString).apply() }
额外的优化建议
为了让代码更健壮、性能更好,还可以做这两个优化:
- 单例化Gson实例:每次解析都创建新的Gson对象会浪费资源,建议全局只创建一个:
之后所有序列化/反序列化操作都用这个实例。private val gson = Gson() - 更安全的空处理:避免使用非空断言
!!,用takeIf和let的组合来处理空值,更符合Kotlin的空安全规范:fun getProductInArrayListWithQuantities(key: String): ArrayList<ProductQuantityData> { val json = sharedPreferences.getString(key, "") return json.takeIf { it.isNotEmpty() }?.let { gson.fromJson(it, object : TypeToken<ArrayList<ProductQuantityData>>() {}.type) } ?: ArrayList() }
内容的提问来源于stack exchange,提问作者Lina
相关产品推荐
相关产品推荐

