Android Coil 3 ImageRequest.Builder error() 和 fallback()异同
摘要:在Coil3的ImageRequest.Builder中,error()和fallback()都用于配置加载失败时的兜底图,但触发条件不同。error()在data非空但加载失败(如网络错误、文件不存在等)时触发;fallback()则在data为空时使用。两者通常与placeholder()配合使用:placeholder()显示加载中,fallback()处理无数据情况,error()处理加载失败。建议同时配置两者以明确区分"无数据"和"加载失败"场景,使语义更清晰。
在 Coil 3 的 ImageRequest.Builder 里,.error() 和 .fallback() 都是用来配置"加载不出目标图片时显示什么"的,但它们触发条件不同。
一句话区分:
.error() :data 非空,但加载/获取/解码失败时使用
.fallback() :data 为空/null 时使用
1. .error() 是什么?
.error() 表示:请求失败时显示的兜底图。
例如:
ImageRequest.Builder(context)
.data(url)
.error(R.drawable.ic_load_failed)
.target(imageView)
.build()
当 data 本身不是 null,但是加载过程中失败,比如:
网络请求失败
HTTP 404
文件不存在
Uri 打不开
权限不足
图片格式不支持
解码失败
图片损坏
Fetcher 抛异常
Decoder 抛异常
这时 Coil 会显示 .error() 配置的 Drawable。
2. .fallback() 是什么?
.fallback() 表示:请求的 data 为 null 时显示的兜底图。
例如:
ImageRequest.Builder(context)
.data(user.avatarUrl) // avatarUrl 可能为 null
.fallback(R.drawable.ic_default_avatar)
.target(imageView)
.build()
当:
user.avatarUrl == null
Coil 不会真的去加载网络或本地图片,而是认为:
这个请求没有有效数据源
此时显示 .fallback() 配置的 Drawable。
3. 核心差异
| 对比项 | .error() |
.fallback() |
|---|---|---|
| 触发条件 | data 非空,但加载失败 |
data == null |
| 代表含义 | 有图片地址/资源,但加载失败 | 本来就没有图片数据 |
| 常见原因 | 网络失败、文件不存在、解码失败、权限失败 | 用户头像为空、封面字段为空、业务没有配置图片 |
| 是否表示异常 | 通常是异常/失败 | 通常是正常业务状态 |
| 典型图片 | 加载失败图、破图图标 | 默认头像、默认封面、空状态图 |
| Listener 回调 | 通常走 onError |
通常也可能作为失败结果处理,但 UI 使用 fallback |
4. 示例:.error() 适用场景
场景 1:图片 URL 有值,但下载失败
val request = ImageRequest.Builder(context)
.data("https://example.com/image.jpg")
.placeholder(R.drawable.ic_loading)
.error(R.drawable.ic_load_failed)
.target(imageView)
.build()
如果 URL 404、网络超时、服务器异常,会显示:
ic_load_failed
场景 2:本地 Uri 有值,但文件不存在或无权限
ImageRequest.Builder(context)
.data(uri)
.error(R.drawable.ic_broken_image)
.target(imageView)
.build()
如果 uri 打不开,或者图片损坏,会显示 .error()。
5. 示例:.fallback() 适用场景
场景 1:用户没有头像
ImageRequest.Builder(context)
.data(user.avatarUrl)
.fallback(R.drawable.ic_default_avatar)
.error(R.drawable.ic_avatar_load_failed)
.target(imageView)
.build()
如果:
user.avatarUrl == null
显示:
ic_default_avatar
如果:
user.avatarUrl != null
但加载失败,显示:
ic_avatar_load_failed
场景 2:列表封面字段为空
ImageRequest.Builder(context)
.data(item.coverUrl)
.fallback(R.drawable.ic_default_cover)
.error(R.drawable.ic_cover_error)
.target(imageView)
.build()
含义是:
coverUrl == null -> 默认封面
coverUrl 有值但加载失败 -> 加载失败图
6. 如果只设置 .error(),没有设置 .fallback() 会怎样?
通常可以理解为:
data == null 时,如果没有 fallback,Coil 会退而使用 error
例如:
ImageRequest.Builder(context)
.data(null)
.error(R.drawable.ic_error)
.target(imageView)
.build()
此时大概率会显示:
ic_error
也就是说,.error() 可以作为更通用的失败兜底图。
但语义上,如果你明确知道 data 可能为空,最好还是单独配置 .fallback()。
7. 如果只设置 .fallback(),加载失败会怎样?
例如:
ImageRequest.Builder(context)
.data("https://example.com/not-exist.jpg")
.fallback(R.drawable.ic_default_avatar)
.target(imageView)
.build()
如果 data 不为空,但加载失败,由于没有设置 .error(),那么 Coil 没有专门的 error 图可显示。
结果可能是:
显示空
保持原图
target.onError(null)
具体表现和 target / ImageView 状态有关。
所以一般建议:
.fallback(...)
.error(...)
一起配置,语义更清晰。
8. .placeholder()、.error()、.fallback() 的关系
这三个经常一起用:
ImageRequest.Builder(context)
.data(url)
.placeholder(R.drawable.ic_loading)
.fallback(R.drawable.ic_default_avatar)
.error(R.drawable.ic_load_failed)
.target(imageView)
.build()
它们的触发阶段不同:
placeholder:加载中显示
fallback :data == null 时显示
error :data 非空但加载失败时显示
流程大致是:
开始请求
↓
显示 placeholder
↓
判断 data
↓
data == null ?
├─ 是:显示 fallback
└─ 否:继续 fetch/decode
↓
成功:显示 result.image
失败:显示 error
9. 在图/媒体场景里的理解
假设加载本地媒体缩略图:
ImageRequest.Builder(context)
.data(media.uri)
.fallback(R.drawable.ic_no_media)
.error(R.drawable.ic_media_broken)
.target(imageView)
.build()
可以这样理解:
media.uri == null
说明业务层没有可加载的媒体地址。
显示:
ic_no_media
这是正常业务兜底。
media.uri != null,但文件被删除
比如数据库里还有记录,但真实文件没了。
显示:
ic_media_broken
这是加载失败。
media.uri != null,但权限丢失
例如 Android 相册权限变化、SAF 授权失效。
显示:
ic_media_broken
这也是加载失败。
10. 推荐用法
如果业务上 data 可能为空,建议这样写:
ImageRequest.Builder(context)
.data(imageUrl)
.placeholder(R.drawable.ic_loading)
.fallback(R.drawable.ic_default_image)
.error(R.drawable.ic_load_failed)
.target(imageView)
.build()
语义清晰:
加载中 -> placeholder
没有图片数据 -> fallback
有数据但加载失败 -> error
加载成功 -> result.image
11. 总结
.error() 和 .fallback() 都是兜底图,但含义不同:
.error()
用于:
有 data,但是加载失败
例如网络错误、文件不存在、解码失败。
.fallback()
用于:
data == null
例如用户没有头像、业务没有封面、媒体 Uri 为空。
推荐理解:
fallback 是"无数据兜底"
error 是"失败兜底"