本文使用两种方式,实现Compose中图片的异步加载
前言
Android开发中异步加载图片是非常常见的需求。本文将带你实现这一需求。 本文将分为如下两个方面:
- 自己写函数
- 用开源库
实现
借助Glide库自己写
Glide开源库基本上成为了Android中加载图片的首选,其简单易用的API和强大的缓存能力让这一过程变得十分方便。 自然在Jetpack Compose中也可以使用。
引入依赖
在模块中的build.gradle 中加入
implementation 'com.github.bumptech.glide:glide:4.12.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
编写函数
如何让Glide把图片加载到Compose组件上去呢?我们可以利用其提供的into(Target) 指定自定义的target,再搭配上mutableState<Bitmap> 的返回值,即可实现在图片加载完成后Compose自动更新 图片加载时一般会有一个默认的loading 图,我们可以如法炮制,让Glide先帮我们加载一张本地图片,然后再去加载网络图片即可。 编写的函数如下:
fun loadImage(
context: Context,
url: String,
@DrawableRes defaultImageId: Int = R.drawable.load_holder
): MutableState<Bitmap?> {
val TAG = "LoadImage"
val bitmapState: MutableState<Bitmap?> = mutableStateOf(null)
val glideUrl = GlideUrl(url,LazyHeaders.Builder().addHeader("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.67").build())
Glide.with(context)
.asBitmap()
.load(defaultImageId)
.into(object : CustomTarget<Bitmap>() {
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
bitmapState.value = resource
}
override fun onLoadCleared(placeholder: Drawable?) {}
})
try {
Glide.with(context)
.asBitmap()
.load(glideUrl)
.into(object : CustomTarget<Bitmap>() {
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
bitmapState.value = resource
}
override fun onLoadCleared(placeholder: Drawable?) {}
})
} catch (glideException: GlideException) {
Log.d(TAG, "loadImage: ${glideException.rootCauses}")
}
return bitmapState
}
使用例子
简单的例子如下:
@Composable
fun LoadPicture(
url : String
){
val imageState = loadImage(
context = LocalContext.current,
url = url,
)
Card(modifier = Modifier
.padding(4.dp)
.clickable { }) {
imageState.value?.let {
Image(
bitmap = it.asImageBitmap(),
contentDescription = "",
modifier = Modifier
.padding(4.dp)
.fillMaxWidth()
)
}
}
}
LazyColumn {
val urls = arrayListOf<String>()
for (i in 500..550){urls.add("https://nyc3.digitaloceanspaces.com/food2fork/food2fork-static/featured_images/$i/featured_image.png")}
itemsIndexed(urls){ _ , url -> LoadPicture(url = url)}
}
效果如下图所示: 加载中
加载完毕 P.S.:别忘了声明网络权限哦!
借助开源框架
事实上,谷歌在其开发文档中也给出了示例,用的是开源库Accompanist 所以我们也可以用这个
简单的例子
implementation "com.google.accompanist:accompanist-coil:0.13.0"
@Composable
fun LoadPicture2(url:String){
val painter = rememberCoilPainter(url)
Box {
Image(
painter = painter,
contentDescription = "",
)
when (painter.loadState) {
is ImageLoadState.Loading -> {
CircularProgressIndicator(Modifier.align(Alignment.Center))
}
is ImageLoadState.Error -> {
Text(text = "发生错误", color = MaterialColors.RedA200)
}
else -> Text(text = "未知情况", color = MaterialColors.PurpleA400)
}
}
}
上面例子中的Material颜色来自开源库 CMaterialColors
效果如下:
P.S.:如果想更好的看到加载的情况,可以在模拟器设置中将网络类型设置为较慢的类型
一些限制
个人感觉,这种方式有以下的问题:
- 滑动加载时不如Glide流畅
- 对Kotlin版本有要求,如(截止文章写作时)最新的
0.13.0 版就必须用kotlin1.5 及以上版本,否则就会编译出错
参考
完结。 如果对我的文章感兴趣,欢迎前往我的Github界面指导!
|