使用 Coil 加载图片
在 Compose 中异步加载图片
使用 Coil 加载图片 是 CoddyKit 上的免费 Android Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Android Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Android Academy 课程共包含 4 节课。
为什么需要图像加载器
大多数现代应用都会显示来自互联网的图片:头像、商品图片和文章缩略图。正确下载并解码这些图片,比看起来要困难得多。
您需要在后台线程中通过网络获取字节,将其解码为位图,进行缓存以避免重复获取,并在用户滚动离开时取消请求。手动完成这些工作很容易出错。
Coil(Coroutine Image Loader,协程图像加载器)通过简洁且适合 Compose 的 API 为您处理这一切。本课中,您将加载第一张远程图片。
将 Coil 添加到项目中
Coil 以 Gradle 依赖项的形式提供。对于 Jetpack Compose,您需要使用 coil-compose 构件,它会提供 AsyncImage 可组合项。
将其添加到模块的 build.gradle.kts 中。Coil 3 是当前的主要版本,支持多种平台;本课使用的是它的 Compose 集成。
// build.gradle.kts (module level)
dependencies {
implementation("io.coil-kt.coil3:coil-compose:3.0.4")
implementation("io.coil-kt.coil3:coil-network-okhttp:3.0.4")
}互联网权限
要从 URL 下载图片,您的应用需要 INTERNET 权限。这是一项普通的(安装时授予的)权限,因此只需在清单中声明即可,不会弹出运行时提示。
没有该权限时,每个网络请求都会因安全异常而失败。
<!-- AndroidManifest.xml -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<application ...>
...
</application>
</manifest>您的第一个 AsyncImage
在 Compose 中显示远程图片的最简单方式是使用 AsyncImage。为它提供一个 model(通常是 URL 字符串)和一个 contentDescription,剩下的工作由 Coil 完成:后台获取、解码和显示。
它会自动使用与组合绑定的协程,因此当可组合项离开屏幕时,请求也会被取消。
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import coil3.compose.AsyncImage
@Composable
fun Avatar() {
AsyncImage(
model = "https://example.com/avatar.png",
contentDescription = "User avatar",
modifier = Modifier.size(96.dp)
)
}contentScale:图片如何适配
图片很少会与布局槽位的确切尺寸完全匹配。ContentScale 用于控制位图如何缩放到其边界内。
ContentScale.Crop会填满容器并裁剪溢出部分(非常适合头像和缩略图)。ContentScale.Fit会保留完整图片,但可能留下空白区域。ContentScale.FillBounds会拉伸图片以填满边界(可能造成变形)。
对于固定尺寸的槽位,最常用的选择是 Crop。
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.dp
import coil3.compose.AsyncImage
@Composable
fun CircleAvatar(url: String) {
AsyncImage(
model = url,
contentDescription = "Avatar",
contentScale = ContentScale.Crop,
modifier = Modifier
.size(80.dp)
.clip(CircleShape)
)
}使用 ImageRequest 构建请求
传入 URL 字符串是快捷方式。如果需要更多控制,可以构建一个 ImageRequest。这样您就能设置淡入、请求头、变换和缓存键等选项。
您需要一个 Context,Compose 会通过 LocalContext.current 提供它。
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import coil3.compose.AsyncImage
import coil3.request.ImageRequest
import coil3.request.crossfade
@Composable
fun ProductImage(url: String) {
val context = LocalContext.current
val request = ImageRequest.Builder(context)
.data(url)
.crossfade(true)
.build()
AsyncImage(
model = request,
contentDescription = "Product photo"
)
}使用淡入实现平滑加载
默认情况下,图片加载完成后会立即显示,可能显得突兀。crossfade(true) 会让图片在一段很短的动画中逐渐淡入。
您也可以传入以毫秒为单位的时长,让淡入速度变慢或变快。这个小细节能让列表的观感精致许多。
import coil3.request.ImageRequest
import coil3.request.crossfade
import android.content.Context
fun smoothRequest(context: Context, url: String) =
ImageRequest.Builder(context)
.data(url)
.crossfade(durationMillis = 300)
.build()从不同来源加载
AsyncImage 中的 model 非常灵活。Coil 可以从多种来源加载图片,而不仅仅是远程 URL:
- 用于网络或本地文件的
String或Uri。 - 可绘制资源 ID(
R.drawable.logo)。 - 设备中的
File。 - 来自照片选择器的内容
Uri。
这意味着同一个可组合项可以无缝处理远程图片和本地图片。
import android.net.Uri
import androidx.compose.runtime.Composable
import coil3.compose.AsyncImage
@Composable
fun FlexibleImage(source: Any) {
// source can be a URL String, a Uri, a File, or a resource id
AsyncImage(
model = source,
contentDescription = null
)
}
// Examples:
// FlexibleImage("https://example.com/pic.jpg")
// FlexibleImage(Uri.parse("content://media/external/images/1"))响应加载状态
有时您需要知道图片正在加载、加载成功还是加载失败,以便显示不同的界面。AsyncImagePainter 会公开该状态,但最简单的方式是使用 SubcomposeAsyncImage,它允许您为每种状态提供不同的内容。
下一课我们会深入介绍占位图;这里先了解感知状态的加载结构。
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.runtime.Composable
import coil3.compose.SubcomposeAsyncImage
@Composable
fun StatefulImage(url: String) {
SubcomposeAsyncImage(
model = url,
contentDescription = "Photo",
loading = { CircularProgressIndicator() }
)
}自动取消请求
Coil 的一大优势是能够自动取消请求。由于 AsyncImage 会在组合中启动请求,当可组合项离开屏幕时(例如某一行滚出 LazyColumn),正在进行的请求就会被取消。
这样可以节省带宽和 CPU,避免执行无用工作。您无需亲自编写任何取消代码,这正是 Coil 能够很好地扩展到长列表的原因。
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import coil3.compose.AsyncImage
@Composable
fun PhotoFeed(urls: List<String>) {
LazyColumn {
items(urls) { url ->
AsyncImage(
model = url,
contentDescription = null,
modifier = Modifier
.fillMaxWidth()
.height(200.dp)
)
}
}
}完整的图片卡片
让我们综合所学内容:创建一张卡片,让远程图片填满顶部区域,使用淡入效果,并裁剪到固定高度。这是您会反复复用的基础模式。
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Card
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import coil3.compose.AsyncImage
import coil3.request.ImageRequest
import coil3.request.crossfade
@Composable
fun ImageCard(title: String, imageUrl: String) {
val context = LocalContext.current
Card(modifier = Modifier.fillMaxWidth().padding(16.dp)) {
Column {
AsyncImage(
model = ImageRequest.Builder(context)
.data(imageUrl)
.crossfade(true)
.build(),
contentDescription = title,
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxWidth().height(180.dp)
)
Text(text = title, modifier = Modifier.padding(16.dp))
}
}
}快速检查
在 Jetpack Compose 中,coil-compose 提供的哪个可组合项是通过 URL 显示远程图片的最简单方式?
回顾
您已经使用 Coil 加载了第一批远程图片。要点如下:
- 添加
coil-compose和 OkHttp 网络依赖项,并添加INTERNET权限。 AsyncImage(model = url, contentDescription = ...)是快捷方式。- 对于头像和缩略图,使用固定尺寸配合
ContentScale.Crop。 - 构建
ImageRequest,以实现淡入效果和更多控制。 - 当可组合项离开屏幕时,Coil 会自动取消正在进行的请求。
下一步:使用占位图和错误状态,让加载过程更自然。
常见问题解答
「使用 Coil 加载图片」课时是免费的吗?
是的 — 「使用 Coil 加载图片」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Android Academy 课程的其余内容,请升级到 CoddyKit PRO。 Android Academy 课程共包含 4 节课。
「使用 Coil 加载图片」这节课中我会学到什么?
在 Compose 中异步加载图片 你通过在浏览器中直接运行的动手代码来练习 Android Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Android Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Android Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。
「使用 Coil 加载图片」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Android Academy 课中编写并运行代码吗?
能。每节 Android Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。