一、介绍
在Android,资源的呈现主要有三大形式:文字、图片、视频。图片有分为本地资源和网络资源。
网络资源需要通过下载然后绑定到ImageView中。
在前期我们使用的图片加载框架如:picasso、gliade、imageload。这些框架都可以满足我们正常的图片加载到显示,且这些框架都是通过Java语言开发出来。接下来,我将介绍一款以kotlin语言开发的框架Coil。
Coil的介绍
一、介绍
是一个 Android 图片加载库,通过Kotlin协程的方式加载图片
优势
-
更快:
Coil 在性能上有很多优化,包括内存缓存和磁盘缓存,把缩略图存保存在内存中,循环利用 bitmap,自动暂停和取消图片网络请求等。 -
更轻量级:
Coil 的包体很小,很多API依赖项目中的其他模块的框架(如:前提是你的 APP 里面集成了 OkHttp 和 Coroutines),Coil 和 Picasso 的方法数差不多,相比 Glide 和 Fresco 要轻量很多,kotlin的语法支持,代码更简洁。 -
更容易使用:
Coil 的 API 充分利用了 Kotlin 语言的新特性,简化和减少了很多样板代码,采用了类方法扩展,常用的API已通过ImageViews扩展到了ImageView中,可以直接使用 -
更流行更新:
Coil 首选 Kotlin 语言开发并且使用包含 Coroutines, OkHttp, Okio 和 AndroidX Lifecycles 在内最流行的开源库,很好的兼容最新Jetpack组件。
2、集成
io.coil-kt:coil-base : 基础组件,提供了基本的图片请求、图片解码、图片缓存等
io.coil-kt:coil : 默认组件,依赖于io.coil-kt:coil-base,提供了 Coil 类的单例对象以及 ImageViews 相关的扩展函数
io.coil-kt:coil-gif : 用于支持解码 GIFs
io.coil-kt:coil-svg : 用于支持解码 SVG
io.coil-kt:coil-video : 包含两个 fetchers 用于支持读取和解码 任何 Android 的支持的视频格式 的视频帧
//依赖库
implementation("io.coil-kt:coil:1.2.2")// //选择添加 implementation("io.coil-kt:coil-gif:1.2.2")//支持GIF implementation("io.coil-kt:coil-svg:1.2.2")//支持SVG implementation("io.coil-kt:coil-video:1.2.2")//支持Video
3、使用
由于在kotlin支持方法的扩展,所以ImageViews已支持提供了load方法,默认只需要传入图片地址即可。
@JvmSyntheticinline fun ImageView.load( uri: String?, imageLoader: ImageLoader = context.imageLoader, builder: ImageRequest.Builder.() -> Unit = {}): Disposable = loadAny(uri, imageLoader, builder)@JvmSyntheticinline fun ImageView.load( url: HttpUrl?, imageLoader: ImageLoader = context.imageLoader, builder: ImageRequest.Builder.() -> Unit = {}): Disposable = loadAny(url, imageLoader, builder)@JvmSyntheticinline fun ImageView.load( uri: Uri?, imageLoader: ImageLoader = context.imageLoader, builder: ImageRequest.Builder.() -> Unit = {}): Disposable = loadAny(uri, imageLoader, builder)@JvmSyntheticinline fun ImageView.load( file: File?, imageLoader: ImageLoader = context.imageLoader, builder: ImageRequest.Builder.() -> Unit = {}): Disposable = loadAny(file, imageLoader, builder)@JvmSyntheticinline fun ImageView.load( @DrawableRes drawableResId: Int, imageLoader: ImageLoader = context.imageLoader, builder: ImageRequest.Builder.() -> Unit = {}): Disposable = loadAny(drawableResId, imageLoader, builder)@JvmSyntheticinline fun ImageView.load( drawable: Drawable?, imageLoader: ImageLoader = context.imageLoader, builder: ImageRequest.Builder.() -> Unit = {}): Disposable = loadAny(drawable, imageLoader, builder)@JvmSyntheticinline fun ImageView.load( bitmap: Bitmap?, imageLoader: ImageLoader = context.imageLoader, builder: ImageRequest.Builder.() -> Unit = {}): Disposable = loadAny(bitmap, imageLoader, builder)
load支持的请求类型
uri: String:图片地址
url: HttpUrl:封装好的请求url
uri: Uri:Uri的资源封装
file: File:文件类型
drawableResId: Int:资源id
drawable: Drawable:drawable对象
bitmap: Bitmap:bitmap对象
加载load,返回一个Disposable,Disposable是IPC的接口,如下
interface Disposable { val isDisposed: Boolean fun dispose() @ExperimentalCoilApi suspend fun await()}
通过Disposable可以判断是否完成,主动调用以及等待。
扩展:
Coil不仅提供了默认的加载,还可以扩展其他。
inline fun ImageView.load( uri: String?, imageLoader: ImageLoader = context.imageLoader, builder: ImageRequest.Builder.() -> Unit = {}): Disposable = loadAny(uri, imageLoader, builder)
通过源码可以看到,requestbuild是支持扩展的。默认后面是{},可以在{}体中调用build中方法。
bind.image.load(url){ //build 扩展体 crossfade(true) //渐进渐出 placeholder(R.mipmap.ic_launcher) //加载中占位图 error(R.mipmap.ic_launcher) //加载失败占位图 allowHardware(true)//硬件加速 allowRgb565(true)//支持565格式 lifecycle(lifecycle)//生命周期关联 var default= DefaultRequestOptions() defaults(default) }
包括网络缓存等,我们可以自己根据业务配置。如果你需要可以自定义一个ImageRequest.Build
ImageView高阶变换
Transformation(图片变换)
- BlurTransformation() : 高斯模糊变换
- CircleCropTransformation() : 圆形裁剪变换
- GrayscaleTransformation() : 灰度变换
- RoundedCornersTransformation() : 圆角变换
高阶图片变形通过transformations()来完成,支持多样式。
BlurTransformation() : 高斯模糊变换
class BlurTransformation @JvmOverloads constructor( private val context: Context, private val radius: Float = DEFAULT_RADIUS, private val sampling: Float = DEFAULT_SAMPLING)
init { require(radius in 0.0..25.0) { "radius must be in [0, 25]." } require(sampling > 0) { "sampling must be > 0." } }
radius:模糊半径范围在0到25之间,数值越大,模糊越深
sampling:采样率必须大于,这个值是进行缩放图片大小的,(0,1),图片是越来越大,[1,++oo),图片是越来越小
GrayscaleTransformation() : 灰度变换
这个主要把彩色的图片置灰,常见特殊忌日,可以设置,利用了ColorMatrixColorFilter对颜色进行过滤。
RoundedCornersTransformation:圆角角度设置
class RoundedCornersTransformation( @Px private val topLeft: Float = 0f, @Px private val topRight: Float = 0f, @Px private val bottomLeft: Float = 0f, @Px private val bottomRight: Float = 0f)
A=topleft ,B=topright,C=bottomLeft,D=bottomRight。
如果只传一个参数,默认就是四个角的角度,角度默认值是0,任何角的坐标都是(x,y),所以你设置角度无法只设置一个叫的一半。
如果想了解view的角度自定义,可以查看:
Android ImageView 四个角自定义角度,以及角度的变换_addroundrect_蜗牛、Z的博客-CSDN博客
参数扩展
有人用习惯了Glide或者imageload,会发现,可以通过配置来管理加载中,加载失败等标识,Coil同样也支持,只是通过build提供的方法来完成。
inline fun ImageView.load( uri: String?, imageLoader: ImageLoader = context.imageLoader, builder: ImageRequest.Builder.() -> Unit = {}): Disposable = loadAny(uri, imageLoader, builder)
bind.load.setOnClickListener { bind.image.load("https://img-blog.csdnimg.cn/3a4114c916904ecbadb7a71b77294eef.gif"){ crossfade(true) //渐进渐出 placeholder(R.mipmap.ic_launcher) //加载中占位图 error(R.mipmap.ic_launcher) //加载失败占位图 allowHardware(true)//硬件加速// transformations(BlurTransformation(context,25f,2f)) //圆角 transformations(RoundedCornersTransformation(90f,0f,0f,0f)) } }
有人会有疑问:
builder: ImageRequest.Builder.() -> Unit = {}
这个写法,是返回builder类,通过指向类的内部方法来完成,最后返回build。
小试牛刀:
class Build { var msgs: String? = "" fun setMsg(msg: String) = apply { this.msgs = msg }}
class TestBody(var build: Build.() -> Unit = {}) { fun log() { var mBuild = Build() mBuild.apply(build) mBuild.msgs?.let { MyLog.log(it) } }}fun main() { var test = TestBody({ setMsg("hello") }) test.log()}
build是一个block object的,我们可以通过Build对象apply方法copy这个对象。
GIF动态图片加载
Coil库不仅支持静态图片,也支持动态图片。只是动态和静态的解析对象不同ComponentRegistry在注册的时候,已提供了各种拦截与支持。
依赖库的引入:
implementation("io.coil-kt:coil-gif:1.2.2")//支持GIF
decoder目前提供两种方式:
api<28
class GifDecoder : Decoder
api>=28
@RequiresApi(28)class ImageDecoderDecoder : Decoder
ImageLoad初始化:
注意GIFDecoder类的顶部注释:
NOTE: Prefer using ImageDecoderDecoder on API 28 and above.
//创建 gif ImageLoader 实例 val imageLoader = ImageLoader.Builder(applicationContext) .componentRegistry { if (SDK_INT >= 28) { add(ImageDecoderDecoder(applicationContext)) } else { add(GifDecoder()) } }.build() //设置全局唯一实例 Coil.setImageLoader(imageLoader)
这样我们就完成了Gif的ImageLoader的设置
如何监听图片加载:
ImageRequest提供了fun listener(listener: Listener?) 方法。
bind.image.load("https://img-blog.csdnimg.cn/3a4114c916904ecbadb7a71b77294eef.gif") { listener(object : ImageRequest.Listener { override fun onCancel(request: ImageRequest) { super.onCancel(request) } override fun onSuccess(request: ImageRequest, metadata: ImageResult.Metadata) { super.onSuccess(request, metadata) } override fun onError(request: ImageRequest, throwable: Throwable) { super.onError(request, throwable) } override fun onStart(request: ImageRequest) { super.onStart(request) } }) }
关于配置
上面都是通过方法设置配置参数,如何设置全局配置?需要我们自己去设置一个全局的 ImageLoader.Builder
val okHttpClient = OkHttpClient.Builder() .cache(CoilUtils.createDefaultCache(this)) .build() val imageLoader = ImageLoader.Builder(this) .availableMemoryPercentage(0.5f) .diskCachePolicy(CachePolicy.ENABLED) //磁盘缓策略 ENABLED、READ_ONLY、WRITE_ONLY、DISABLED .crossfade(true) //淡入淡出 .okHttpClient { //设置okhttpClient实例 okHttpClient }.build() Coil.setImageLoader(imageLoader)
api介绍:
1.availableMemoryPercentage:
设置用于此 ImageLoader 的内存缓存和位图池的可用内存百分比,如果设置了百分百,那么cache将会失效
//源码 fun availableMemoryPercentage(@FloatRange(from = 0.0, to = 1.0) percent: Double) = apply { require(percent in 0.0..1.0) { "Percent must be in the range [0.0, 1.0]." } this.availableMemoryPercentage = percent this.memoryCache = null }
2.memoryCachePolicy :
内存缓存策略,有4中策略;
3.diskCachePolicy:
磁盘缓存策略,方式和内存策略一致;
CachePolicy.ENABLED : 可读可写
CachePolicy.READ_ONLY : 只读
CachePolicy.WRITE_ONLY : 只写
CachePolicy.DISABLED : 不可读不可写,即禁用
短视频首帧
Coil还有特别特别项,支持短视频首帧图片加载。正常在项目中,如果该项目有短视频业务,在视频不播放的状态下,如何获取首帧图片?这个问题是很多公司思考的问题。
大公司在处理视频首帧都是通过服务器跑的。这样,在视频集在列表展示只处理单张图片即可。针对某一个视频,特别是小公司的时候,Coil明显很友好,可以在接收的范围类,降低技术和服务器的成本。
依赖库的引入:
implementation("io.coil-kt:coil-video:1.2.2")//支持Video
添加VideoDecoder
//创建 gif ImageLoader 实例 val imageLoader = ImageLoader.Builder(applicationContext) .componentRegistry { add(VideoFrameDecoder(context)) }.build() //设置全局唯一实例 Coil.setImageLoader(imageLoader)
剩余的设置,都是通用设置,如果项目需要支持GIF、VideoFrame,可以同时支持进去,都是通过componentRegistry add添加,可以追加进去。
来源地址:https://blog.csdn.net/qq36246172/article/details/129764778