Coil的原理浅析与自定义加载类型

一、前言

Coil是一种纯粹是一kotlin编写的,利用了协程特性的图片加载库,其代码量较少,算是比较轻量的图片加载库。对于常规类型的图片都有加载方式,不过也有无法预料的情况,比如加载apk文件中的图片,此文章基于此问题进行编写。

二、Coil

Coil在内部的协程采用了大量的AndroidX-LifeCycle,所以其与生命周期绑定,大量函数采取挂起suspend的方式,可以在对其拓展时候进行直接使用异步协程。其对于数据的请求和操作采用了OkHttp,倘若项目中使用了OkHttp,可以让两者进行共用一个OkHttp
Coil主要有ImageLoaderImageReuqestInterceptorMapperKeyerCacheFetchImageResultDecordeTargetTransformationsTransitions组成。其中资源获取和处理过程为InterceptorMapperKeyerCacheFetchImageResultDecorde。除了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

但是如果想新增类型的话需要拓展MapperFetcher。其中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)

四、参考链接

  1. Android图片加载【神器】—Coil源码解析

  2. Coil

  3. Extending the Image Pipeline

猜你喜欢

转载自blog.csdn.net/Mr_Tony/article/details/129875539