Android Coil 3 ImageRequest.Builder error() 和 fallback()异同

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 是"失败兜底"
相关推荐
三少爷的鞋3 小时前
别再靠 Code Review 守底线:我做了一个静态分析项目 RedLine
android
y = xⁿ11 小时前
DeepSeek Harness 学习日记:关于Agent接口,工具调用的底层实现
android·java·学习
2601_9620664913 小时前
【Sql Server】Update中的From语句,以及常见更新操作方式
android·java·数据库
用户693717500138419 小时前
曾经安卓开发人手一个的 EventBus,为什么现在没人爱用了?
android·android studio
九皇叔叔20 小时前
MySQL ORDER BY 性能优化详解:Using filesort、联合索引、ASC/DESC 与覆盖索引
android·adb
bytebitx21 小时前
MacOS 编译腾讯 Mars XLog 及使用(已16KB对齐)
kotlin·mac·apk
OriginCoding21 小时前
用 AI Agent 协作完成一个 Android TOTP 应用:从需求边界到 v1.0.0
android·ai编程
杉氧1 天前
React 灵魂:深入剖析 Hooks 与副作用(Side Effects)陷阱
android·前端·react native
又见情义1 天前
RK3568 + RTL8211F 网络唤醒(WOL)功能适配全记录
android·网络·驱动开发
用户0934077735141 天前
HarmonyOS WPS Open SDK 实践:registerApp 鉴权与就绪门禁
android·typescript·harmonyos