注册

Android 新一代图片加载库 - Coil

Coil 是 Android 的新一代图片加载库,它的全名叫做 Coroutine Image Loader,即协程图片加载器,用于显示网络或本地图像资源。


特点



  • 快速:执行了多项优化,包括内存和磁盘缓存,图像降采样,自动暂停/取消请求等。
  • 轻量级:依赖于 Kotlin,协程和 Okio,并与谷歌的 R8 等代码缩减器无缝协作。
  • 易于使用:API 利用 Kotlin 的语言特性来实现简洁性和最小化的样板代码。
  • 现代化:以 Kotlin 为首要语言,并与协程,Okio,Ktor 和 OkHttp 等现代库实现互操作。

加载图片


先引入依赖


implementation(libs.coil)

最简单的加载方法就是使用这个扩展函数了


inline fun ImageView.load(
data: Any?,
imageLoader: ImageLoader = context.imageLoader,
builder: ImageRequest.Builder.() -> Unit = {}
)
: Disposable {
val request = ImageRequest.Builder(context)
.data(data)
.target(this)
.apply(builder)
.build()
return imageLoader.enqueue(request)
}

使用扩展函数来加载本地或网络中的图片


// 加载网络图片
binding.imageView.load("https://img2.huashi6.com/images/resource/2020/07/12/h82924904p0.jpg")
// 加载资源图片
binding.imageView.load(R.drawable.girl)
// 加载文件中的图片
val file = File(requireContext().getExternalFilesDir(null), "saved_image.jpg")
binding.imageView.load(file.absolutePath)

支持设置占位图,裁剪变换,生命周期关联等


binding.imageView.load("https://img2.huashi6.com/images/resource/2020/07/12/h82924904p0.jpg") {
crossfade(true) //渐进渐出
crossfade(1000) //渐进渐出时间
placeholder(R.mipmap.sym_def_app_icon) //加载占位图
error(R.mipmap.sym_def_app_icon) //加载失败占位图
allowHardware(true) //硬件加速
allowRgb565(true) //支持565格式
lifecycle(lifecycle) //生命周期关联
transformations(CircleCropTransformation()) //圆形裁剪变换
}

变为圆角矩形


binding.imageView.load("https://img2.huashi6.com/images/resource/2020/07/12/h82924904p0.jpg") {
lifecycle(lifecycle)
transformations(RoundedCornersTransformation(20f))
}

可以创建自定义的图片加载器,为其添加一些日志拦截器等。


class LoggingInterceptor : Interceptor {

companion object {
private const val TAG = "LoggingInterceptor"
}

override suspend fun intercept(chain: Interceptor.Chain): ImageResult {
val url = chain.request.data.toString()
val width = chain.size.width.toString()
val height = chain.size.height.toString()
Log.i(TAG, "url: $url, width: $width, height: $height")
return chain.proceed(chain.request)
}
}

class MyApplication : Application(), ImageLoaderFactory {

override fun newImageLoader() =
ImageLoader.Builder(this.applicationContext).components { add(LoggingInterceptor()) }
.build()
}

替换 Okhttp 实例


val okHttpClient = OkHttpClient.Builder()
.retryOnConnectionFailure(true)
.connectTimeout(30, TimeUnit.SECONDS)
.writeTimeout(20, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.build()
val imageLoader = ImageLoader.Builder(requireContext()).okHttpClient {
okHttpClient
}.build()
Coil.setImageLoader(imageLoader)
binding.imageView.load("https://img2.huashi6.com/images/resource/2020/07/12/h82924904p0.jpg")

加载 gif


添加依赖


implementation(libs.coil.gif)

按照官方的做法,设置 ImageLoader。


val imageLoader = ImageLoader.Builder(requireContext())
.components {
if (SDK_INT >= 28) {
add(ImageDecoderDecoder.Factory())
} else {
add(GifDecoder.Factory())
}
}.build()
Coil.setImageLoader(imageLoader)
binding.imageView.load(GIF_URL)

下载监听


可以监听下载过程


binding.imageView.load(IMAGE_URL) {
listener(
onStart = {
Log.i(TAG, "onStart")
},
onError = { request, throwable ->
Log.i(TAG, "onError")
},
onSuccess = { request, result ->
Log.i(TAG, "onSuccess")
},
onCancel = { request ->
Log.i(TAG, "onCancel")
}
)
}

取消下载


val disposable = binding.imageView.load(IMAGE_URL)
disposable.dispose()

对 Jetpack Compose 的支持


引入依赖:


implementation(libs.coil.compose)

使用 AsyncImage


@Composable
@NonRestartableComposable
fun AsyncImage(
model: Any?,
contentDescription: String?,
modifier: Modifier = Modifier,
transform: (State) -> State = DefaultTransform,
onState: ((State) -> Unit)? = null,
alignment: Alignment = Alignment.Center,
contentScale: ContentScale = ContentScale.Fit,
alpha: Float = DefaultAlpha,
colorFilter: ColorFilter? = null,
filterQuality: FilterQuality = DefaultFilterQuality,
clipToBounds: Boolean = true,
modelEqualityDelegate: EqualityDelegate = DefaultModelEqualityDelegate,
)


比如显示一张网络图片,就可以这样干。


@Composable
fun DisplayPicture() {
AsyncImage(
model = "https://img2.huashi6.com/images/resource/2020/07/12/h82924904p0.jpg",
contentDescription = null
)
}

支持设置占位图,过程监听,裁剪等


@Composable
fun DisplayPicture() {
AsyncImage(
modifier = Modifier
.clip(CircleShape)
.size(200.dp),
onSuccess = {
Log.i(TAG, "onSuccess")
},
onError = {
Log.i(TAG, "onError")
},
onLoading = {
Log.i(TAG, "onLoading")
},
model = ImageRequest.Builder(LocalContext.current)
.data("https://img2.huashi6.com/images/resource/2020/07/12/h82924904p0.jpg")
.crossfade(true)
.placeholder(R.drawable.default_image)
.error(R.drawable.default_image)
.build(),
contentScale = ContentScale.Crop,
contentDescription = null
)
}

这里介绍一下这个 ContentScale,它是用来指定图片如何适应其容器大小的,有以下几个值:



  • ContentScale.FillBounds:图片会被拉伸或压缩以完全填充其容器的宽度和高度,这可能会导致图片的宽高比失真。
  • ContentScale.Fit:图片会保持其原始宽高比,并尽可能大地缩放以适应容器,同时确保图片的任一边都不会超出容器的边界,这可能会导致容器的某些部分未被图片覆盖。
  • ContentScale.Crop:图片会被裁剪以完全覆盖其容器的宽度和高度,同时保持图片的宽高比,这通常用于需要确保整个容器都被图片覆盖的场景,但可能会丢失图片的一部分内容。
  • ContentScale.FillWidth:图片会保持其原始宽高比,并调整其高度以完全填充容器的宽度,这可能会导致图片的高度超出容器的高度,从而被裁剪或需要额外的布局处理。
  • ContentScale.FillHeight:图片会保持其原始宽高比,并调整其宽度以完全填充容器的高度,这可能会导致图片的宽度超出容器的宽度,从而需要相应的处理。
  • ContentScale.Inside:图片会保持其原始宽高比,并缩放以确保完全位于容器内部,同时其任一边都不会超出容器的边界。
  • ContentScale.:图片将以其原始尺寸显示,不会进行任何缩放或裁剪。

作者:阿健君
来源:juejin.cn/post/7403546034763235378

0 个评论

要回复文章请先登录注册