本文已参与「新人创作礼」活动,一起开启掘金创作之路。
Image Loaders¶
ImageLoader是服务对象, 用来执行ImageRequest. 它们处理缓存, 数据获取, 图片解码, 请求管理, Bitmap池技术, 内存管理, 等等. 新实例可以通过构建者进行创建和配置:
val imageLoader = ImageLoader.Builder(context)
.crossfade(true)
.build()
Coil在应用范围内创建单例ImageLoader并共享时, 性能最好. 这是因为每一个ImageLoader实例有它自己的内存缓存, 硬盘缓存和OkHttpClient实例.
缓存¶
每一个ImageLoader实例保留了最近解码的Bitmap的内存缓存, 也保留了从网络加载的图片的硬盘缓存. 两者可以在创建ImageLoader实例的时候进行配置:
val imageLoader = ImageLoader.Builder(context)
.memoryCache {
MemoryCache.Builder(context)
.maxSizePercent(0.25)
.build()
}
.diskCache {
DiskCache.Builder(context)
.directory(context.cacheDir.resolve("image_cache"))
.maxSizePercent(0.02)
.build()
}
.build()
在图片加载之后, ImageResult返回了key, 通过使用key可以访问图片的内存缓存和硬盘缓存. 而ImageResult是由ImageLoader.execute返回或者在ImageRequest.Listener.onSuccess和ImageRequest.Listener.onError里面.
注意
Coil 1.x依赖于OkHttp的存盘缓存. Coil 2.x拥有了自己的硬盘缓存, 并且不应该使用OkHttp的Cache.
单例 vs 依赖注入¶
默认的Coil构件(io.coil-kt:coil)包含单例ImageLoader, 它可以通过扩展函数context.imageLoader进行访问.
Coil在应用范围内创建单例ImageLoader并共享时, 性能最好. 这是因为每一个ImageLoader实例拥有自己的资源集.
单例ImageLoader可以在类Application内通过实现ImageLoaderFactory接口进行配置.
候选情况下, 你可以创建自己的ImageLoader实例并且通过像Dagger一样的依赖注入器将它们注入. 如果这样做的话, 一定要依赖io.coil-kt:coil-base库, 因为它不创建单例ImageLoader.
测试¶
ImageLoader是个接口, 可能通过假实现进行替换.
举个例子, 可以创建假的ImageLoader实现来一直同步地返回相同的Drawable:
class FakeImageLoader(private val context: Context) : ImageLoader {
override val defaults = DefaultRequestOptions()
override val components = ComponentRegistry()
override val memoryCache: MemoryCache? get() = null
override val diskCache: DiskCache? get() = null
override fun enqueue(request: ImageRequest): Disposable {
// Always call onStart before onSuccess.
request.target?.onStart(request.placeholder)
val result = ColorDrawable(Color.BLACK)
request.target?.onSuccess(result)
return object : Disposable {
override val job = CompletableDeferred(newResult(request, result))
override val isDisposed get() = true
override fun dispose() {}
}
}
override suspend fun execute(request: ImageRequest): ImageResult {
return newResult(request, ColorDrawable(Color.BLACK))
}
private fun newResult(request: ImageRequest, drawable: Drawable): SuccessResult {
return SuccessResult(
drawable = drawable,
request = request,
dataSource = DataSource.MEMORY_CACHE
)
}
override fun newBuilder() = throw UnsupportedOperationException()
override fun shutdown() {}
}
这非常适合于需要一致渲染行为的屏幕截图和测试.