本文使用两种方式,实现Compose中图片的异步加载
前言
Android开发中异步加载图片是非常常见的需求。本文将带你实现这一需求。
本文将分为如下两个方面:
- 自己写函数
- 用开源库
实现
借助Glide库自己写
Glide开源库基本上成为了Android中加载图片的首选,其简单易用的API和强大的缓存能力让这一过程变得十分方便。
自然在Jetpack Compose中也可以使用。
引入依赖
在模块中的build.gradle
中加入
1 2
| 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先帮我们加载一张本地图片,然后再去加载网络图片即可。
编写的函数如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
|
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 }
|
使用例子
简单的例子如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| @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
所以我们也可以用这个
简单的例子
1
| implementation "com.google.accompanist:accompanist-coil:0.13.0"
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
@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) } } }
|
效果如下:
P.S.:如果想更好的看到加载的情况,可以在模拟器设置中将网络类型设置为较慢的类型
一些限制
个人感觉,这种方式有以下的问题:
- 滑动加载时不如Glide流畅
- 对Kotlin版本有要求,如(截止文章写作时)最新的
0.13.0
版就必须用kotlin1.5
及以上版本,否则就会编译出错
参考