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

如何让Glide将PaletteBitmap存入磁盘缓存,避免重复生成Palette?

实现PaletteBitmap的磁盘缓存方案

当然可行!这完全是Glide设计中支持的场景——通过自定义ResourceEncoder,我们可以让你的PaletteBitmap类型被序列化并写入磁盘缓存,彻底避免重复生成Palette的开销。下面我会一步步带你完成实现:

1. 确保PaletteBitmap可序列化

首先,你的PaletteBitmap需要支持序列化,这样才能被写入磁盘。由于Bitmap默认不实现Serializable,我们需要手动处理它的序列化逻辑。这里推荐把PaletteBitmap改成普通类(而非data class,避免自动生成的方法干扰序列化):

class PaletteBitmap(val bitmap: Bitmap, val palette: Palette) : Serializable {

    @Throws(IOException::class)
    private fun writeObject(out: ObjectOutputStream) {
        out.defaultWriteObject()
        // 将Bitmap压缩为PNG写入输出流
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, out)
    }

    @Throws(ClassNotFoundException::class, IOException::class)
    private fun readObject(`in`: ObjectInputStream) {
        `in`.defaultReadObject()
        // 从输入流中解码Bitmap
        val decodedBitmap = BitmapFactory.decodeStream(`in`)
        // 反射替换成员变量(因为val不可变,这里需要用反射或者改成var)
        val bitmapField = PaletteBitmap::class.java.getDeclaredField("bitmap")
        bitmapField.isAccessible = true
        bitmapField.set(this, decodedBitmap)
    }
}

注意:如果用Kotlin的data class,自动生成的equals/hashCode可能会影响序列化,所以普通类更稳妥。另外,Palette本身已经实现了Serializable,所以直接序列化即可。

2. 实现自定义ResourceEncoder

接下来我们需要实现ResourceEncoder接口,它负责将PaletteBitmap资源编码并写入磁盘文件:

class PaletteBitmapEncoder : ResourceEncoder<PaletteBitmap> {

    override fun encode(
        resource: Resource<PaletteBitmap>,
        cacheFile: File,
        options: Options
    ): Boolean {
        val paletteBitmap = resource.get()
        return try {
            // 使用ObjectOutputStream序列化PaletteBitmap到缓存文件
            ObjectOutputStream(FileOutputStream(cacheFile)).use { outputStream ->
                outputStream.writeObject(paletteBitmap)
            }
            true
        } catch (e: IOException) {
            e.printStackTrace()
            false
        }
    }

    override fun getEncodeStrategy(options: Options): EncodeStrategy {
        // 我们直接序列化整个对象,所以使用SOURCE策略
        return EncodeStrategy.SOURCE
    }
}
  • EncodeStrategy.SOURCE表示直接写入原始数据(这里是序列化后的对象),而TRANSCODE是用于将资源转码为其他格式(比如Bitmap转成JPG),所以这里选SOURCE更合适。

3. 在GlideModule中注册Encoder

最后一步,我们需要把自定义的PaletteBitmapEncoder注册到Glide的组件系统中,让Glide知道处理PaletteBitmap类型时用这个Encoder写入磁盘缓存:

@GlideModule
class MyAppGlideModule : AppGlideModule() {

    override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
        // 注册PaletteBitmap的磁盘缓存编码器
        registry.append(PaletteBitmap::class.java, PaletteBitmapEncoder())
        // 别忘了注册你之前实现的Transcoder
        registry.append(Bitmap::class.java, PaletteBitmap::class.java, PaletteBitmapTranscoder())
    }
}

一定要给这个类加上@GlideModule注解,Glide会在编译时自动生成相关代码,确保组件被正确注册。

4. 验证缓存效果

完成以上步骤后,你可以通过以下方式验证磁盘缓存是否生效:

  • 查看Glide的磁盘缓存目录(默认路径:/sdcard/Android/data/[你的包名]/cache/image_manager_disk_cache/),会看到对应请求的缓存文件;
  • 在PaletteBitmapTranscoder的transcode方法中添加日志,首次加载时会执行生成Palette的逻辑,再次加载时会直接从磁盘缓存读取PaletteBitmap,不会进入transcode方法。

额外注意事项

  • 序列化性能:序列化大Bitmap可能会有一定性能开销,但Glide的磁盘缓存操作是在后台线程执行的,不会影响主线程;
  • 缓存键一致性:只要你的Glide请求参数(比如图片Uri、变换参数等)不变,Glide就会使用相同的缓存键,确保命中缓存;
  • 兼容性:ObjectOutputStream序列化的对象在不同Android版本间兼容性良好,但如果后续修改PaletteBitmap的结构,需要注意序列化版本问题(可以添加private static final long serialVersionUID = 1L;来控制版本)。

内容的提问来源于stack exchange,提问作者Thibault Seisel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 04:02:13