Android 无法通过Gson将含自定义ClothModel的ArrayList保存到SharedPreferences
问题排查与修复方案
核心故障点
- ClothModel1包含不可直接序列化的Bitmap字段:Gson默认无法对Bitmap对象做序列化处理,转JSON时会抛出异常或生成无效内容,导致从SharedPreferences读取数据失败。
- 数据加载时机错误:onCreate中初始化Adapter时,还未执行缓存数据加载逻辑,Adapter绑定的是空列表;后续加载完成后直接替换
clothList对象,Adapter持有的仍是旧的空列表引用,调用notifyDataSetChanged也不会生效。 - 空catch块吞异常:
loadClothList抛出的序列化、反序列化异常被直接捕获丢弃,无法定位具体报错原因。 - 逻辑冗余:每次进入Activity只要携带了
bitmapStr参数,就会新增一条数据到列表,会导致重复数据堆积;且如果进入Activity时没有携带新图片参数,不会触发缓存加载,已保存的列表无法渲染。
修复步骤
1. 调整实体类结构
不要在ClothModel1中存储Bitmap对象,改为存储图片的URL/本地路径字符串,Bitmap在Adapter渲染时再异步加载(可使用Glide、Coil等图片加载框架实现),修改后实体类示例:
// 修改前(错误):包含Bitmap字段 // data class ClothModel1(val title: String, val bitmap: Bitmap) // 修改后(正确):存储图片地址字符串 data class ClothModel1(val title: String, val imgUrl: String)
提示:如果必须存储Bitmap,需要自定义Gson TypeAdapter将Bitmap转为Base64字符串序列化,但强烈不推荐该方案,Base64编码后的Bitmap体积过大,会严重拖慢SharedPreferences读写性能。
2. 调整初始化逻辑
将缓存数据加载放到Adapter初始化之前执行,且不要直接替换clothList对象,复用同一列表实例避免Adapter绑定失效。
3. 删除空catch块,避免吞异常
修复后完整代码示例
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_recycler_view) val recyclerView: RecyclerView = findViewById(R.id.recyclerView) val layoutManager = LinearLayoutManager(this) // 先加载缓存数据,再初始化Adapter loadClothList() clothesAdapter = ClothesAdapter(clothList) recyclerView.layoutManager = layoutManager recyclerView.itemAnimator = DefaultItemAnimator() recyclerView.adapter = clothesAdapter val bitmapStr = intent.getStringExtra("bitmapStr") // 只有携带新图片参数时才新增数据,避免每次进入都重复添加 if (!bitmapStr.isNullOrEmpty()) { thread { // 如有需要可在这里将网络图片保存到本地,存储本地路径到实体类 val imgUrl = bitmapStr runOnUiThread { prepareClothData(imgUrl) } } } } private fun saveClothList() { val sharedPreferences = getSharedPreferences("preferences", MODE_PRIVATE) val editor = sharedPreferences.edit() val gson = Gson() val json = gson.toJson(clothList) editor.putString("clothlist", json) editor.apply() } private fun loadClothList() { val sharedPreferences = getSharedPreferences("preferences", MODE_PRIVATE) val gson = Gson() val json = sharedPreferences.getString("clothlist", null) val type: Type = object : TypeToken<ArrayList<ClothModel1>>() {}.type val tempList: ArrayList<ClothModel1>? = gson.fromJson(json, type) // 复用原有clothList实例,不要直接替换对象 clothList.clear() if (!tempList.isNullOrEmpty()) { clothList.addAll(tempList) } } private fun prepareClothData(imgUrl: String) { loadClothList() val cloth = ClothModel1("title", imgUrl) clothList.add(cloth) saveClothList() // 用notifyItemInserted性能更好 clothesAdapter.notifyItemInserted(clothList.size - 1) }
内容的提问来源于stack exchange,提问作者ktsakiris
相关产品推荐
相关产品推荐

