如何让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
相关产品推荐
相关产品推荐

