用Glide扩展图片加载,使其支持阿里云的OSS访问

    公司有款产品使用了阿里云的服务。

    在之前的版本中,手机明文持有Key,拿到Key后可以进行上传操作。上传结束将返回的url(http开头)上传给服务器,服务器进行保存。

    这本来是个正常的逻辑,但是在后面我们遇到了搞鬼的,他拿到了Key并且开始上传黄色图片。

    这时我们需要进行方案二,用户不持有key,登陆之后才能从服务器拿到key,并且key是有有效期限的,需要定时获取。服务器负责与阿里云进行key的交互。上传之后我们拿到的不再是以http开头的url(http://xxxx.jpg),而是一个以oss开头的后面跟着一段字符串的url(oss://xxxssdddfffggg)。服务器的图片地址也已这个形式保存

    很安全的样子对不对。而且关键是,阿里云已经帮我们做好了上传下载的功能。哇,好方便。但是,这跟原有的图片访问不兼容啊。Glide只支持url,resource等访问,oss开头是阿里云才支持的格式,如何解决呢。

    首先我们想到的是自己实现了个图片三级缓存,并且在调用阶段,根据字符串开头判断是用普通的网络请求还是用阿里云的sdk。功能实现了,而且效果不错。但是几天写出来的框架,会有Glide那么大的工程性能好吗。持着这样的怀疑,我决定模仿Glide的框架去优化我的框架。

    写着写着发现了ModelLoader这个类。发现不一般,打开文档查看发现它支持我们扩展访问类型。不错,我们来实现一下。

 

####9月27日更新####

以下均为kotlin实现

    1.首先ModelLoader这个类就是Glide用来针对不同地址头使用不同加载方式产生的。Glide需要根据地址头来调用对应的加载方式。这个加载方式就是DataFetcher,这里先实现DataFetcher。

import xxx.aliyun.AliyunOssClient
import com.bumptech.glide.Priority
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.data.DataFetcher
import java.io.InputStream

class AliyunOSSDataFetcher(private val model: String) : DataFetcher<InputStream> {
    val ossClient = AliyunOssClient()
    override fun getDataClass(): Class<InputStream> {
        return InputStream::class.java
    }

    override fun cleanup() {
    }

    override fun getDataSource(): DataSource {
        return DataSource.REMOTE
    }

    override fun cancel() {
        ossClient.cancel()
    }

    override fun loadData(priority: Priority, callback: DataFetcher.DataCallback<in InputStream>) {

        ossClient.download(model, object : AliyunOssClient.LoadCallback {
            override fun onLoadComplete(inputStream: InputStream) {
                callback.onDataReady(inputStream)
            }

            override fun onLoadFailed(exception: Exception) {
                callback.onLoadFailed(exception)
            }

        })

    }
}

    这里的ossClient在Glide调用loadData时,需要下载图片,并把结果通过callback返回给Glide。ossClient的具体实现就不具体写了,可以根据阿里云的文档进行实现,主要是返回inputStream给callback.onDataReady()

    2.然后是ModelLoader

import com.bumptech.glide.load.Options
import com.bumptech.glide.load.model.GlideUrl
import com.bumptech.glide.load.model.ModelLoader
import com.bumptech.glide.load.model.ModelLoader.LoadData
import java.io.InputStream
class AliyunOSSModelLoader : ModelLoader<String, InputStream> {
    override fun buildLoadData(model: String, width: Int, height: Int, options: Options): LoadData<InputStream>? {
        return LoadData<InputStream>(GlideUrl(model), AliyunOSSDataFetcher(model))
    }

    override fun handles(model: String): Boolean {
        return model.startsWith("oss:")
    }
}

    这里就很明显了,是给Glide判断用的,如果是oss:开头,那么久用AliyunOssDataFetcher加载

    3.然后是实现一个ModelLoaderFactory

import com.bumptech.glide.load.model.ModelLoader
import com.bumptech.glide.load.model.ModelLoaderFactory
import com.bumptech.glide.load.model.MultiModelLoaderFactory
import java.io.InputStream

class AliyunOSSModelLoaderFactory :ModelLoaderFactory<String,InputStream> {
    override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader<String, InputStream> {
        return AliyunOSSModelLoader()
    }

    override fun teardown() {

    }
}

    4.最后一步,给Glide加载注释@GlideModule,让其生成配置

import android.content.Context
import xxx.utillib.image.glide.AliyunOSSModelLoaderFactory
import xxx.utillib.util.FileUtil
import com.bumptech.glide.Glide
import com.bumptech.glide.GlideBuilder
import com.bumptech.glide.Registry
import com.bumptech.glide.annotation.GlideModule
import com.bumptech.glide.load.engine.cache.DiskLruCacheFactory
import com.bumptech.glide.load.engine.cache.LruResourceCache
import com.bumptech.glide.module.AppGlideModule
import java.io.InputStream

@GlideModule
class CustomGlideModule : AppGlideModule() {
    override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
        registry.prepend(String::class.java, InputStream::class.java, AliyunOSSModelLoaderFactory())
    }

    override fun applyOptions(context: Context, builder: GlideBuilder) {
        super.applyOptions(context, builder)
        var defaultMemoryCacheSize = 8 * 1024 * 1024L
        val runtimeMemoryCacheSize = Runtime.getRuntime().maxMemory() / 8
        val defaultDiskCacheSize = 250 * 1024 * 1024L
        if (runtimeMemoryCacheSize > defaultDiskCacheSize) {
            defaultMemoryCacheSize = runtimeMemoryCacheSize
        }
        builder.setMemoryCache(LruResourceCache(defaultMemoryCacheSize))
                .setDiskCache(DiskLruCacheFactory(FileUtil.get().getCachePath(context, FileUtil.Companion.CacheCategory.PICTURE), defaultDiskCacheSize))

    }
}

    至此大家应该可以实现了

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值