Glide 配置与 下载进度监听 与 ssl证书绕过

下文将介绍Glide扩展的3种使用方式,希望对你有所帮助:

1、利用Glide清理缓存

2、Glide默认配置设置 — AppGlideModule

3、实现Glide加载图片进度监听


利用Glide清理缓存

一般我们在使用Glide的时候,在清理缓存有些很好的理由。

一个原因是调试,要确保Glide 没有从内存或磁盘加载图像。

另一个原因时由于Glide的缓存机制,在加载越来越多图片的时候,磁盘空间会占用越来越多,所以需要允许用户清除一些磁盘空间。

对此,Glide提供了两种方式可用于清理缓存,如下代码所示:

lifecycleScope.launchWhenCreated {

            //第一种方式

            withContext(Dispatchers.IO) {

              Glide.get(this@MainActivity).clearDiskCache()

            }

            //第二种方式

            withContext(Dispatchers.Main) {

                Glide.get(this@MainActivity).clearMemory()

            }

        }



clearDiskCache:只能在后台进行调用,所以我们在子线程调用此方法

clearMemory:只能在主线程进行调用

Glide默认配置设置 — AppGlideModule

在使用Glide链式调用的时候,它会默认使用自带的缓存目录,缓存大小,磁盘缓存策略等,但是在一些场景中,由于缓存大小限制,指定缓存路径,或者多个地方等等,那么就需要自己定义这些配置,所以就要用到AppGlideModule;

首先我们需要创建一个自定义OkHttpGlideModule 让它继承AppGlideModule类,实现它的空方法:

@GlideModule

class OkHttpGlideModule : AppGlideModule() {

override fun isManifestParsingEnabled(): Boolean {

return false

    }

override fun registerComponents(context: Context, glide: Glide, registry: Registry) {

val trustAllCerts =arrayOf(object : X509TrustManager {

override fun checkClientTrusted(

chain: Array?, authType: String?

) {

}

override fun checkServerTrusted(

chain: Array?, authType: String?

) {

}

override fun getAcceptedIssuers(): Array? {

return arrayOf()

}

}

)

val sslContext = SSLContext.getInstance("SSL")

sslContext.init(null, trustAllCerts, SecureRandom())

val sslSocketFactory = sslContext.socketFactory

        val builder = OkHttpClient.Builder()

builder.sslSocketFactory(sslSocketFactory,

            TrustAllCertsTrustManager()

)

builder .addNetworkInterceptor{ chain->

                val request = chain.request()

val response = chain.proceed(request)

val listener = DispatchingProgressManager()

response.newBuilder()

.body(ProgressResponseBody(request.url, response.body!!, listener))

.build()

}

        builder.hostnameVerifier{ _, _-> true }

        registry.replace(

GlideUrl::class.java,

            InputStream::class.java,

            OkHttpUrlLoader.Factory(builder.build())

)

}

}



通过applyOptions方法传入了GlideBuilder实例,它本身就是单例的,可以在这里去修改它里面的那些配置项,不再使用默认值。

可设置bitmap复用缓存池,使用自带的LruBitmapPool可设置当前缓冲池容量最大值,也可以自定义缓存池。

//设置bitmap对象复用缓存池

builder.setBitmapPool(LruBitmapPool(1024*1024*32)


可配置当前磁盘缓存目录和最大缓存 

builder.setDiskCache(

            //配置磁盘缓存目录和最大缓存

            DiskLruCacheFactory(

                (context.externalCacheDir ?: context.cacheDir).absolutePath,

                "imageCache",

                1024 * 1024 * 50

            )

        )


可配置相关图片加载选项,在这里设置placeHolder加载图,error错误图等等,一般来说这些选项都可以进行统一使用的,这样就不用每次都自己单独设置,会显得有点冗余;都可以在AppGlideModule中进行配置。


builder.setDefaultRequestOptions {

    return@setDefaultRequestOptions RequestOptions()

        .placeholder(android.R.drawable.ic_menu_upload_you_tube)

        .error(android.R.drawable.ic_menu_call)

        .centerCrop()

        .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)

        .format(DecodeFormat.DEFAULT)

        .encodeQuality(90)

}



最后需要加上@GlideModule注解,这样在编译阶段 Glide 就可以通过 APT 解析到我们的这一个实现类,然后将我们的配置参数设置为默认值。

值得注意的事项

如果使用AppGlideModule,要避免被混淆,需要在proguard-rules.pro加入相应规则。

-keep public class * implements com.bumptech.glide.module.GlideModule

-keep class * extends com.bumptech.glide.module.AppGlideModule {

<init>(...);



并且在一个应用中只允许存在一个AppGlideModule,创建多个会直接报错。

实现Glide加载图片进度监听

有时候在加载一些过大的图和网络速度偏慢的时候,加载图像往往都需要几秒钟,甚至更久,为了增加用户体验,我们往往会设置loading状态或者显示加载进度条;前者比较简单,后者虽然添加加载进度条并不难,但很不幸的是,Glide 并没有公开下载进度监听器。为了监听 Glide 的下载进度,你需要重写 Glide 模块并提供你自己的OkHttp集成。

添加Glide 注解和 OkHttp 集成

直接在build.gradle文件中加入相应依赖:


kapt 'com.github.bumptech.glide:compiler:4.12.0'

implementation("com.github.bumptech.glide:okhttp3-integration:4.11.0") {

    exclude group: 'glide-parent'

}


这里需要注意的是,要在顶部加入相应插件,并且不要使用annotationProcessor,这样新定义的模块将不会使用,也不会报任何错误,如果你使用的是Kotlin编写,那就用kapt,它是Kotlin的注释处理器;

plugins {id 'kotlin-kapt'}


创建监听接口

首先要创建ResponseProgressListener接口,是用来监听当前url下载进度进行更新操作:

//通知正在监听该url下载进度的操作

interface ResponseProgressListener {

    fun update(url: HttpUrl, byteRead: Long, contentLength: Long)

}


创建OnProgressBarListener接口,获取当前进度并且刷新UI中的ProgressBar,可以获取当前进度百分比(0-100%)。





//监听progressbar进度

interface OnProgressBarListener {

    val currentPercentage:Float

    fun onProgress(bytesRead: Long, expectedLength: Long)

}



创建DispatchingProgressManager

主要用来跟踪所有图片URL的进度和通知UI监听器更新主线程中的进度条状态。


class DispatchingProgressManager internal constructor() : ResponseProgressListener {

    companion object {

        //显示当前url的进度

        private val PROGRESSES = HashMap<String?, Long>()

        //存储UI监听器

        private val LISTENERS = HashMap<String?, OnProgressBarListener>()

        //将url和进度监听器存入到hashmap中

        internal fun expect(url: String?, listener: OnProgressBarListener) {

            LISTENERS[url] = listener

        }

        //如果下载完成/下载失败,移除

        internal fun forget(url: String?) {

            LISTENERS.remove(url)

            PROGRESSES.remove(url)

        }

    }

    //后台线程通知进度,ui线程处理UI

    private val handler: Handler = Handler(Looper.getMainLooper())

    override fun update(url: HttpUrl, byteRead: Long, contentLength: Long) {

        val key = url.toString()

        //如果没有进度监听器,直接显示照片

        val listener = LISTENERS[key] ?: return

        if (contentLength <= byteRead) {

            forget(key)

        }

        if (needsDispatch(key, byteRead, contentLength, listener.currentPercentage)) { //8

            Log.d("glide", "update: $contentLength")

            handler.post { listener.onProgress(byteRead, contentLength) }

        }

    }

    private fun needsDispatch(key: String, current: Long, total: Long, granularity: Float): Boolean {

        if (granularity == 0f || current == 0L || total == current) {

            return true

        }

        val percent = 100f * current / total

        val currentProgress = (percent / granularity).toLong()

        val lastProgress = PROGRESSES[key]

        return if (lastProgress == null || currentProgress != lastProgress) {

            PROGRESSES[key] = currentProgress

            true

        } else {

            false

        }

    }

}



简单来说,该类主要就是创建两个HashMap分别存放当前图片加载进度和UI监听器Listener,同时在needsDispatch方法中计算当前进度百分比,存入到定义好的HashMap中,然后通过handler更新UI组件;对外提供来个方法expect和forget,前者将URL 及其UI 监听器添加到HashMap,在下载开始时调用;或者在下载完成/下载失败的时候调用,移除当前定义的URL。

OkHttp 的 ResponseBody 中监听进度

在内部根据 contentLength 和已读取到的流字节数来,然后将它们的值传入到我们已经定义好的progressListener中。


class ProgressResponseBody internal constructor(

    private val url: HttpUrl,

    private val responseBody: ResponseBody,

    private val progressListener: ResponseProgressListener

) : ResponseBody() {

    private var bufferedSource: BufferedSource? = null

    override fun contentType(): MediaType? {

        return responseBody.contentType()

    }

    override fun contentLength(): Long {

        return responseBody.contentLength()

    }

    override fun source(): BufferedSource {

        if (bufferedSource == null) {

            bufferedSource = Okio.buffer(source(responseBody.source()))

        }

        return this.bufferedSource!!

    }

    private fun source(source: Source): Source {

        return object : ForwardingSource(source) {

            var totalBytesRead = 0L

            @Throws(IOException::class)

            override fun read(sink: Buffer, byteCount: Long): Long {

                val bytesRead = super.read(sink, byteCount)

                val fullLength = responseBody.contentLength()

                if (bytesRead.toInt() == -1) { // this source is exhausted

                    totalBytesRead = fullLength

                } else {

                    totalBytesRead += bytesRead

                }

                progressListener.update(url, totalBytesRead, fullLength)

                return bytesRead

            }

        }

    }

}



自定义的AppGlideModule中扩展

接着需要在之前定义MyAppGlide中重写registerComponents方法,这里使用我们自己的OkHttpClient,添加相应的拦截器Interceptor,并将之前已经定义好的DispatchingProgressManager传入进来;同时,提供了一个OkHttpUrlLoader.Factory类方便替换Glide 的默认网络库。



封装GlideProgressUtil加载图片

最后在前面所有准备工作都完成了,我们需要将当前显示的ImageView和ProgressBar组件拿到,对外提供一个load方法加载图片,在该方法中调用expected方法存储进度和初始化侦听器,同时更新ProgressBar的进度,在下载开始的时候让它可见,下载结束后隐藏。

/**

*

* @description

* @author as752497576@gmail.com

* @time 2023/3/12

*/

class GlideProgressUtil {

    //加载图片

    fun loadTest(  ) {

        val apkUrl =

            "https://meeting.onlineinline.com/api/ossUpgrade/A/A/1.3.3/app-release-sign-8c979ad0d.apk"

        DispatchingProgressManager.expect(apkUrl, object : OnProgressBarListener { //4

            override val currentPercentage: Float //5

                get() = 1.0f

            override fun onProgress(bytesRead: Long, expectedLength: Long) {

                AppLog.getInstance().e(" onProgress: ${(100 * bytesRead / expectedLength).toInt()} ")

                AppLog.getInstance().e(" onProgress:=== ${(100 * bytesRead / expectedLength).toInt()} ")

            }

        })

        Glide.with(BaseApplication.mContext)

            .downloadOnly()

            .load(apkUrl)

            .listener(object : RequestListener<File> {

                override fun onLoadFailed(

                    e: GlideException?,

                    model: Any,

                    target: Target<File>,

                    isFirstResource: Boolean

                ): Boolean {

                    AppLog.getInstance().e("第三方的速度 下载失败onResourceReady: $e")

                    DispatchingProgressManager.forget(apkUrl)

                    return false

                }

                override fun onResourceReady(

                    resource: File,

                    model: Any,

                    target: Target<File>,

                    dataSource: DataSource,

                    isFirstResource: Boolean

                ): Boolean {

//                        Toast.makeText(getContext(), "下载成功", Toast.LENGTH_SHORT).show();

                    DispatchingProgressManager.forget(apkUrl)

                    AppLog.getInstance().e("第三方的速度onResourceReady: $resource")

                    AppLog.getInstance().e("第三方的速度model: $model")

                    AppLog.getInstance().e("第三方的速度model: $target")

                    AppLog.getInstance().e("第三方的速度dataSource: $dataSource")

                    AppLog.getInstance().e("第三方的速度onResourceReady: $isFirstResource")

                    return false

                }

            })

            .preload()

    }

}


SSL证书绕过

在上述代码中,使用了Glide公开的资源监听器,可以图片加载失败/成功的时候执行相应的操作,这里无论下载失败还是下载成功,都将图片URL移除,同时隐藏ProgressBar。

自此,我们就完成了利用Glide实现了图片加载进度监听。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容