一個(gè)舊項(xiàng)目需要添加僅wifi下加載圖片的配置功能,因?yàn)樵擁?xiàng)目并沒有封裝圖片加載,只是直接使用了glide加載圖片,常規(guī)改造方法工作量巨大,于是有了這篇。
實(shí)現(xiàn)思路是通過自定義的Loader,實(shí)現(xiàn)wifi下正常邏輯,非wifi下跳過下載流程。
官方文檔,https://muyangmin.github.io/glide-docs-cn/tut/custom-modelloader.html
自定義Fetcher
這個(gè)類是圖片下載的核心邏輯。
class NewsFetcher(private val client: Call.Factory, private val url: GlideUrl) :
DataFetcher<InputStream>, okhttp3.Callback {
private val TAG = NewsFetcher::class.java.name
@Volatile
private var call: Call? = null
private var callback: DataFetcher.DataCallback<in InputStream>? = null
private var stream: InputStream? = null
private var responseBody: ResponseBody? = null
override fun loadData(priority: Priority, callback: DataFetcher.DataCallback<in InputStream>) {
if (不滿足下載圖片的情況) {
return
}
//使用okhttp 請(qǐng)求圖片
val requestBuilder = Request.Builder().url(url.toStringUrl())
for ((key, value) in url.headers) {
requestBuilder.addHeader(key, value)
}
val request = requestBuilder.build()
this.callback = callback
call = client.newCall(request)
call?.enqueue(this)
}
override fun cleanup() {
try {
stream?.close()
} catch (e: IOException) {
// Ignored
}
responseBody?.close()
callback = null
}
override fun cancel() {
val local = call
local?.cancel()
}
override fun getDataClass(): Class<InputStream> = InputStream::class.java
override fun getDataSource(): DataSource = DataSource.REMOTE
override fun onFailure(call: Call, e: IOException) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "OkHttp failed to obtain result", e)
}
callback?.onLoadFailed(e)
}
override fun onResponse(call: Call, response: Response) {
responseBody = response.body()
if (response.isSuccessful) {
val contentLength =
Preconditions.checkNotNull(responseBody).contentLength()
stream = ContentLengthInputStream.obtain(responseBody!!.byteStream(), contentLength)
callback?.onDataReady(stream)
} else {
callback?.onLoadFailed(HttpException(response.message(), response.code()))
}
}
}
ModelLoader
- 定義一個(gè)okhttp單例
object NewsInternalClient {
val internalClient: Call.Factory = OkHttpClient()
}
- modelLoader
class NewsModelLoader(private val client: Call.Factory) : ModelLoader<GlideUrl, InputStream> {
override fun handles(url: GlideUrl): Boolean {
return true
}
override fun buildLoadData(
model: GlideUrl,
width: Int,
height: Int,
options: Options
): ModelLoader.LoadData<InputStream>? {
return ModelLoader.LoadData(model,
NewsFetcher(client, model)
)
}
class Factory : ModelLoaderFactory<GlideUrl, InputStream> {
override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader<GlideUrl, InputStream> {
return NewsModelLoader(NewsInternalClient.internalClient)
}
override fun teardown() {
// Do nothing, this instance doesn't own the client.
}
}
}
LibraryGlideModule
因?yàn)槲业倪壿嬍窃趍odule中,所以使用LibraryGlideModule,如果你的實(shí)在app module則使用AppGlideModule。
@GlideModule
class NewsGlideModel : LibraryGlideModule() {
override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
registry.replace(
GlideUrl::class.java, InputStream::class.java,
NewsModelLoader.Factory()
)
}
}
最后
到這里你的配置還不會(huì)生效,需要在app module中編寫一個(gè)空的AppGlideModule
@GlideModule
public class MyAppGlideModel extends AppGlideModule {
}
在使用到glide注解的模塊添加處理器
kapt 'com.github.bumptech.glide:compiler:4.11.0'
大功告成,正常使用glide即可。