Android 入门教程
图片加载
本教程共 100 篇 · 第 90 篇 · 更新于 2026-07-28 · 约 7 分钟阅读
AndroidAndroid 入门教程Coil图片加载Glide缓存
90. 图片加载
本节目标:学会用 Coil 在 Compose 里加载网络图片,掌握缓存策略、占位图、变换、列表优化,了解和 Glide/Picasso 的选型差异。
应用里几乎处处要加载图片:用户头像、商品图、新闻配图。直接用 BitmapFactory 解码会卡 UI、占内存、没缓存。专业的图片加载库帮你解决一切。
主流图片库对比
| 库 | 出品方 | Compose 原生 | 现在用不用 |
|---|---|---|---|
| Coil | Coil 团队(Kotlin-first) | 是(AsyncImage) | 推荐,新项目首选 |
| Glide | BumpTech | 通过 Accompanist | 主流,老项目广泛使用 |
| Picasso | Square | 否 | 用得少了,新项目不推荐 |
| Fresco | 否 | 重型,特殊场景才用 |
Coil 是 Kotlin-first 设计,API 简洁,Compose 原生支持,体积小。本教程主线。
TipGlide 老项目维护成本可控,不用强迁。新项目直接上 Coil,体验更好。
加依赖
dependencies {
implementation("io.coil-kt:coil-compose:2.7.0")
}
网络权限(加载网络图需要):
<uses-permission android:name="android.permission.INTERNET" />
基本用法
Compose 里用 AsyncImage:
AsyncImage(
model = "https://example.com/avatar.jpg",
contentDescription = "用户头像",
modifier = Modifier.size(64.dp)
)
加载网络、本地文件、资源都支持:
AsyncImage(
model = R.drawable.placeholder,
contentDescription = null
)
AsyncImage(
model = File("/sdcard/photo.jpg"),
contentDescription = null
)
AsyncImage(
model = Uri.parse("content://media/external/images/1"),
contentDescription = null
)
占位图和错误图
加载中显示占位图,加载失败显示错误图:
AsyncImage(
model = ImageRequest.Builder(LocalContext.current)
.data("https://example.com/avatar.jpg")
.crossfade(true) // 淡入动画
.placeholder(R.drawable.placeholder)
.error(R.drawable.error)
.build(),
contentDescription = "头像",
modifier = Modifier.size(64.dp)
)
或者用更简洁的 SubcomposeAsyncImage,能用 Composable 当占位:
SubcomposeAsyncImage(
model = "https://example.com/avatar.jpg",
contentDescription = null,
loading = { CircularProgressIndicator() },
error = { Text("加载失败") }
)
变换
圆形、圆角、模糊等:
// 圆形
AsyncImage(
model = ImageRequest.Builder(LocalContext.current)
.data("https://example.com/avatar.jpg")
.transformations(CircleCropTransformation())
.build(),
contentDescription = "头像"
)
// 圆角
.transformations(RoundedCornersTransformation(16f))
// 模糊
.transformations(BlurTransformation(LocalContext.current, 25f))
Compose 里也能用 Modifier:
AsyncImage(
model = "https://...",
contentDescription = null,
modifier = Modifier
.size(64.dp)
.clip(CircleShape)
)
缓存
Coil 默认两级缓存:内存 + 磁盘。
- 内存缓存:Bitmap 存在内存,最快。应用关了就没。
- 磁盘缓存:图片文件存本地,下次启动还在。
默认策略:
- 内存:存原始 Bitmap。
- 磁盘:按 URL 哈希存,默认 250MB。
自定义缓存策略:
val imageLoader = ImageLoader.Builder(context)
.memoryCache {
MemoryCache.Builder(context)
.maxSizePercent(0.25) // 占可用内存 25%
.build()
}
.diskCache {
DiskCache.Builder()
.directory(context.cacheDir.resolve("image_cache"))
.maxSizeBytes(100L * 1024 * 1024) // 100MB
.build()
}
.build()
// 全局设置
Coil.setImageLoader(imageLoader)
Note默认策略已经够用,普通项目不用自定义。需要精细控制(比如预加载某类图片)再调。
控制缓存行为
ImageRequest.Builder(context)
.data(url)
.memoryCachePolicy(CachePolicy.DISABLED) // 不读内存缓存
.diskCachePolicy(CachePolicy.ENABLED)
.build()
策略:
ENABLED:用缓存。DISABLED:不用缓存。READ_ONLY:只读不写。WRITE_ONLY:只写不读。
列表性能
长列表加载图片,要避免卡顿:
- 固定尺寸:给
AsyncImage设Modifier.size(...),不固定会触发测量多次。 - 用
key():列表项有稳定 key,避免重组错位。 - 降采样:Coil 自动按
ImageView大小降采样,不用管。 crossfade(false):列表里关掉淡入,避免重复动画。
LazyColumn {
items(users, key = { it.id }) { user ->
AsyncImage(
model = user.avatarUrl,
contentDescription = user.name,
modifier = Modifier.size(48.dp)
)
}
}
预加载
提前加载图片,用户滚动到时立即显示:
val imageLoader = LocalContext.current.imageLoader
val request = ImageRequest.Builder(context)
.data(url)
.size(128)
.build()
LaunchedEffect(Unit) {
imageLoader.enqueue(request)
}
加载状态监听
val painter = rememberAsyncImagePainter(
model = ImageRequest.Builder(LocalContext.current)
.data(url)
.listener(
onStart = { /* 开始加载 */ },
onSuccess = { _, result -> /* 成功 */ },
onError = { _, result -> /* 失败 */ }
)
.build()
)
Image(
painter = painter,
contentDescription = null
)
GIF 动图
implementation("io.coil-kt:coil-gif:2.7.0")
val imageLoader = ImageLoader.Builder(context)
.components {
if (SDK_INT >= 28) {
add(ImageDecoderDecoder.Factory())
} else {
add(GifDecoder.Factory())
}
}
.build()
AsyncImage(
model = "https://example.com/animation.gif",
contentDescription = null
)
SVG 矢量图
implementation("io.coil-kt:coil-svg:2.7.0")
val imageLoader = ImageLoader.Builder(context)
.components {
add(SvgDecoder.Factory())
}
.build()
AsyncImage(
model = "https://example.com/icon.svg",
contentDescription = null
)
常见坑
contentDescription忘写:无障碍读不出,写null表示装饰性图片。- 不设尺寸:列表里尺寸不固定导致测量多次,卡顿。
- 加载本地大图不降采样:OOM。Coil 默认按目标尺寸降采样,但要给目标尺寸。
- 网络图加载失败没错误图:用户体验差。
- 同一 URL 多处加载重复请求:Coil 自动去重,不用担心。
- GIF 不加 gif 依赖:只显示第一帧。
小结
Coil 是 Kotlin-first 图片库,Compose 原生支持。AsyncImage 加载网络/本地/资源图,ImageRequest.Builder 配置占位图、变换、缓存策略。两级缓存默认够用,列表里固定尺寸 + key() 保性能。GIF 和 SVG 要加额外依赖。
下一章讲传感器,看怎么读加速度、陀螺仪等数据。