一、前言
Coil
是一种纯粹是一kotlin
编写的,利用了协程特性的图片加载库,其代码量较少,算是比较轻量的图片加载库。对于常规类型的图片都有加载方式,不过也有无法预料的情况,比如加载apk文件中的图片,此文章基于此问题进行编写。
二、Coil
Coil
在内部的协程采用了大量的AndroidX-LifeCycle
,所以其与生命周期绑定,大量函数采取挂起suspend
的方式,可以在对其拓展时候进行直接使用异步协程。其对于数据的请求和操作采用了OkHttp
,倘若项目中使用了OkHttp
,可以让两者进行共用一个OkHttp
。
Coil
主要有ImageLoader
、 ImageReuqest
、Interceptor
、Mapper
、Keyer
、Cache
、Fetch
、ImageResult
、Decorde
、Target
、Transformations
、Transitions
组成。其中资源获取和处理过程为Interceptor
、Mapper
、Keyer
、Cache
、Fetch
、ImageResult
、Decorde
。除了ImageResult
都可以覆盖拓展。
val imageLoader = ImageLoader.Builder(context)
.components {
add(CustomCacheInterceptor())
add(ItemMapper())
add(HttpUrlKeyer())
add(CronetFetcher.Factory())
add(GifDecoder.Factory())
}
.build()
三、自定义拓展类型
Coil
自身支持的类型有
String
HttpUrl
Uri
File
Int
Drawable
Bitmap
但是如果想新增类型的话需要拓展Mapper
、Fetcher
。其中Mapper
是对用于区分不同的类型,比如将String类型转换为File
或者Uri
。如果是全新的类型,也可以不做处理,只用处理Fetcher
既可。如果想使用Coil
的缓存,需要拓展Keyer
,否则是没有缓存的。如果返回的图片类型是全新的图片类型,还需要拓展Decoder
解码器。当然所有的操作都可以在Interceptor
处理,不过这里需要注意的是Interceptor
默认为主线程。如果耗时操作需要考虑异步操作,因为Coil
大量使用协程挂起函数,所以开启异步操作也是比较方便的。这里开始演示如果获取apk文件中的图片。
首先定义apk的数据类ApkFileBean
:
data class ApkFileBean(
val appName: String = "",
val path: String = "",
val appSize: Long = 0L,
val time: Long = System.currentTimeMillis(),
val icon: Drawable ?= null,
var isCheck: Boolean = false,
)
定义数据获取类Fetch
:
//参考coil中的DrawableFetcher.kt
class ApkFetcher(private val apkFileBean: ApkFileBean, private val context: Context) : Fetcher {
override suspend fun fetch(): FetchResult {
var drawable = CommonUtil.getApkIcon(context, apkFileBean.path) ?: ColorDrawable(Color.TRANSPARENT)
if (drawable is VectorDrawable || drawable is VectorDrawableCompat){
drawable = ColorDrawable(Color.TRANSPARENT)
}
return DrawableResult(drawable, false,dataSource = DataSource.MEMORY)
}
class Factory(private val context: Context) : Fetcher.Factory<ApkFileBean> {
override fun create(data: ApkFileBean, options: Options, imageLoader: ImageLoader): Fetcher {
return ApkFetcher(data,context)
}
}
}
新增缓存Keyer
:
class ApkKeyer : Keyer<ApkFileBean> {
override fun key(data: ApkFileBean, options: Options): String {
return "apk_${
data.path}"
}
}
然后进行初始化即可:
private fun initCoil() {
val loader = ImageLoader.Builder(this).components {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
add(ImageDecoderDecoder.Factory())
} else {
add(GifDecoder.Factory())
}
add(VideoFrameDecoder.Factory())
add(ApkFetcher.Factory(getInstance()))
add(ApkKeyer())
}.build()
Coil.setImageLoader(loader)
}
使用方式和其余一样,不需要做特殊操作:
val apkBean = ApkFileBean("这里写apk文件的地址")
ImageView.load(apkBean)