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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.14 01:15:02