需求
假设此时已经用load
指定一个url: String
,又用into
指定了一个img: ImageView
开始加载,但是网络突然中断,导致图片加载失败。在这种情况下,想要通过点击一个Button
重新加载。
kotlin
Glide.with(context).load(url)
.placeholder(loadingBitmap)
.into(img) // 失败后将保持 loadingBitmap
分析1
自然的想法是直接添加一个按钮,在失败时重复执行加载过程:
kotlin
button.setOnClickListener {
Glide.with(context).load(url)
.placeholder(loadingBitmap)
.into(img) // 失败后将保持 loadingBitmap
}
但是这样做每次点击按钮都会重新执行一遍Glide的构建流程,浪费处理资源。
分析2
在Glide处理时增加一个监听器,只有onLoadFailed
亦即加载失败时,才将按钮设为可点击,并且撤销之前的监听器。同时,为按钮增加一个监控变量,确保其只被点击了一次,避免重复加载(退化为分析1
)。
代码比较复杂,这里略去不写。
分析3
实际上Glide自身存在控制资源重新加载的方式,即Target
。因此,不需要任何重初始化,只要调用Target
的相关函数刷新加载请求即可。
解决方案
将分析3
编写为一个简单的类如下。
kotlin
class RequestReloadingButtonListener<T>(private val button: Button) : RequestListener<T> {
var mTarget: Target<T>? = null
init {
button.apply { post {
setOnClickListener { mTarget?.request?.apply {
clear() // 取消上次请求
begin() // 异步开始新请求
} }
} }
}
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<T>,
isFirstResource: Boolean
): Boolean {
button.visibility = View.VISIBLE // 显示重加载按钮
mTarget = target // 记录请求目标
return false
}
override fun onResourceReady(
resource: T & Any,
model: Any,
target: Target<T>?,
dataSource: DataSource,
isFirstResource: Boolean
): Boolean {
button.visibility = View.GONE // 隐藏重加载按钮
return false
}
}
这样一来,通过如下代码即可实现加载失败时显示重加载按钮,用户点击后重新加载:
kotlin
Glide.with(context).load(url)
.placeholder(loadingBitmap)
.addListener(RequestReloadingButtonListener(button))
.into(img)