美文网首页
Glide 配置与 下载进度监听 与 ssl证书绕过

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

作者: 善良的老农 | 来源:发表于2023-03-11 15:46 被阅读0次

下文将介绍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实现了图片加载进度监听。

相关文章

网友评论

      本文标题:Glide 配置与 下载进度监听 与 ssl证书绕过

      本文链接:https://www.haomeiwen.com/subject/iwbfmttx.html