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