一、Glide基本使用

在Android中,加载图片最好用的就是Glide了,至于为什么呢,不多说,Google都推荐了,Google的很多官方Demo都是用Glide加载网络图片的。

Glide使用步骤如下:

  1. 使用AndroidStudio创建一个GlideDemo项目,选择Kotlin语言
  2. 添加Glide依赖
implementation 'com.github.bumptech.glide:glide:4.11.0'
  1. 添加权限
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
  1. 使用Glide加载图片
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        Glide.with(this)
                .load("http://192.168.1.250:8080/cat.jpg")
                .centerCrop()
                .placeholder(R.mipmap.ic_launcher)
                .into(imageView)
    }
}

OK,就是这么简单就完成了图片的加载,上面Glide中各函数的功能大家如果不懂的话去官网看一下就知道了,这里不多解释。本篇文章主要是讲加载https的图片。

二、加载Https图片

使用上面的代码去加载一些网络上的https图片一般是没有问题的,没问题是因为网络上的https使用的证书一般是权威机构颁发的证书,而这些权威机构的根证书在手机出厂时就已经预装在手机里面了,所以我们加载https图片时会自动完成认证,但是突然有一天,我们公司的网络请求也改成了Https了,用的是自定义证书,并不是权威机构颁发的,所以这个时候加载公司的https的图片时就加载失败了,异常如下:

Glide: Load failed for https://192.168.1.250:8080/cat.jpg with size [1080x162]
class com.bumptech.glide.load.engine.GlideException: Failed to load resource
There was 1 cause:
javax.net.ssl.SSLHandshakeException(java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.)

看到CertPathValidatorException(证书路径验证器异常)不用我多说应该也知道是什么原理导致的了。

在服务器改成https请求的时候,我是先处理的普通请求,比如登录请求,这些请求都是使用OkHttp实现的,所以我开始时找OkHttp配置自定义证书的实现,而且也实现了,所以这里只讲怎么设置让Glide使用OkHttp来下载图片,而且是使用我们配置过的(即设置好自定证书的)OkHttp对象来下载图片。当然,如果你用的是其它的网络请求框架,如果该网络请求框架也被Glide支持的话,则也可以参考我这个文章来集成的。

刚开始我百度找答案,答案是有,但是写的很不清楚,于是只能靠自己了,去Glide官网找答案,这里记录一下,希望对大家有所帮助,集成OkHttp步骤如下:

  1. 添加Glide中的更多依赖
// OkHttp网络请求库
implementation 'com.squareup.okhttp3:okhttp:4.8.1'
// Glide图片加载库
implementation 'com.github.bumptech.glide:glide:4.11.0'
// Glide集成OkHttp时需要使用的库
implementation "com.github.bumptech.glide:okhttp3-integration:4.11.0"
// Glide需要处理注解时的依赖库,用于处理注解并生成java类
kapt 'com.github.bumptech.glide:compiler:4.11.0'

上面的依赖中使用到了注解处理,所以还需要添加注解处理器插件,添加在gradle文件的最前面的位置:

apply plugin: 'kotlin-kapt'
  1. 创建一个类继承AppGlideModule,这个类名可以随意,如下:
@GlideModule
class OkHttpGlideModule : AppGlideModule() {
    override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
        val okHttpClient = OkHttpClient.Builder().build()
        registry.replace(GlideUrl::class.java, InputStream::class.java, OkHttpUrlLoader.Factory(okHttpClient))
    }
}

网络百度的那些答案这一步是各种覆盖各种类,其实根本就不用,我们自己创建一个OkHttp对象传给Glide即可,这样Glide就会使用我们创建的OkHttp对象来下载图片了,对于具体怎么配置OkHttp可以接受自定义证书,请看我的这篇文章,为了完整性,这里简单实现一个忽略所有证书的实现代码如下:

@GlideModule
class OkHttpGlideModule : AppGlideModule() {

    override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
        val builder = OkHttpClient.Builder()
        builder.sslSocketFactory(sSLSocketFactory, trustManager)
        val okHttpClient = builder.build()
        registry.replace(GlideUrl::class.java, InputStream::class.java, OkHttpUrlLoader.Factory(okHttpClient))
    }
    
    /** 获取一个SSLSocketFactory */
    val sSLSocketFactory: SSLSocketFactory
        get() = try {
            val sslContext = SSLContext.getInstance("SSL")
            sslContext.init(null, arrayOf(trustManager), SecureRandom())
            sslContext.socketFactory
        } catch (e: Exception) {
            throw RuntimeException(e)
        }

    /** 获取一个忽略证书的X509TrustManager */
    val trustManager: X509TrustManager
        get() = object : X509TrustManager {
            override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) { }	
            override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String) { }	
            override fun getAcceptedIssuers(): Array<X509Certificate> { return arrayOf() }
        }
}
  1. 最后还有一步,第2步创建的类中使用了注解,Glide会自动生成一个GlideApp的类,这个类就是使用了我们配置的OkHttp的,所以在下载图片时,我们要使用GlideApp来代替之前的Glide类,如下:
GlideApp.with(this)
                .load("https://192.168.1.250:8080/cat.jpg")
                .centerCrop()
                .placeholder(R.mipmap.ic_launcher)
                .into(imageView)