java – 用于base64图像的Custom Glide ModelLoader

我有来自一些在base64中编码的SOAP API的图像.要使用Glide直接加载它我决定编写自定义ModelLoader.

滑翔版:4.3.1

滑行载重线:

GlideApp.with(activity)
        .load(Data().apply { code = licensePlateData.licensePlateImgId })
        .into(view.imageLicense)

GlideModule:

@GlideModule
class MyAppGlideModule : AppGlideModule() {

    override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
        super.registerComponents(context, glide, registry)
        val app = context.applicationContext as MyApplication
        registry.append(Data::class.java, ByteArray::class.java, MyImageLoaderFactory(app.api))
    }
}

装载机:

class MyImageLoaderFactory(private val api: Api) : ModelLoaderFactory<Data, ByteArray> {

    override fun teardown() {

    }

    override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader<Data, ByteArray> {
        return MyImageLoader(api)
    }
}

class MyImageLoader(private val api: Api) : ModelLoader<Data, ByteArray> {

    override fun buildLoadData(model: Data, width: Int, height: Int, options: Options): ModelLoader.LoadData<ByteArray> {
        val key = "code:${model.code};width:$width;height:$height"
        return ModelLoader.LoadData<ByteArray>(ObjectKey(key), MyImageDataFetcher(api, GetimageRequest().apply { data = model }))
    }

    override fun handles(model: Data): Boolean {
        return true
    }
}

class MyImageDataFetcher(private val api: Api, private val request: GetimageRequest) : DataFetcher<ByteArray> {

    private val disposables = Compositedisposable()

    override fun cleanup() {
        disposables.clear()
    }

    override fun loadData(priority: Priority, callback: DataFetcher.DataCallback<in ByteArray>) {
        api.getimage(request) //soap request
                .map { it.image.decodeBase64() } //translate String to ByteArray
                .subscribe({ callback.onDataReady(it) }, {
                    if (it is Exception) {
                        callback.onLoadFailed(it)
                    } else {
                        callback.onLoadFailed(MyException(it))
                    }
                })
                .addTo(disposables)
    }

    override fun cancel() {
        disposables.clear()
    }

    override fun getDataClass(): Class<ByteArray> {
        return ByteArray::class.java
    }

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

}

堆栈跟踪/ LogCat:

com.bumptech.glide.Registry$NoSourceEncoderAvailableException: Failed to find source encoder for data class: class [B
    at com.bumptech.glide.Registry.getSourceEncoder(Registry.java:534)
    at com.bumptech.glide.load.engine.DecodeHelper.getSourceEncoder(DecodeHelper.java:232)
    at com.bumptech.glide.load.engine.sourceGenerator.cacheData(SourceGenerator.java:74)
    at com.bumptech.glide.load.engine.sourceGenerator.startNext(SourceGenerator.java:45)
    at com.bumptech.glide.load.engine.DecodeJob.runGenerators(DecodeJob.java:298)
    at com.bumptech.glide.load.engine.DecodeJob.runWrapped(DecodeJob.java:268)
    at com.bumptech.glide.load.engine.DecodeJob.run(DecodeJob.java:229)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
    at java.lang.Thread.run(Thread.java:764)
    at com.bumptech.glide.load.engine.executor.GlideExecutor$DefaultThreadFactory$1.run(GlideExecutor.java:413)

我认为我错过了让它发挥作用的东西.

解决方法:

感谢https://github.com/bumptech/glide/issues/2677评论,我找到了解决方案.

@GlideModule
class MyAppGlideModule : AppGlideModule() {

    override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
        super.registerComponents(context, glide, registry)
        val app = context.applicationContext as MyApplication
        registry.append(Data::class.java, ByteBuffer::class.java, MyImageLoaderFactory(app.api))
    }
}

class MyImageLoaderFactory(private val api: Api) : ModelLoaderFactory<Data, ByteBuffer> {

    override fun teardown() {

    }

    override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader<Data, ByteBuffer> {
        return MyImageLoader(api)
    }
}

class MyImageLoader(private val api: Api) : ModelLoader<Data, ByteBuffer> {

    override fun buildLoadData(model: Data, width: Int, height: Int, options: Options): ModelLoader.LoadData<ByteBuffer> {
        val key = "code:${model.code};width:$width;height:$height"
        return ModelLoader.LoadData<ByteBuffer>(ObjectKey(key), MyImageDataFetcher(api, GetimageRequest().apply { data = model }))
    }

    override fun handles(model: Data): Boolean {
        return true
    }
}

class ClmImageDataFetcher(private val api: Api, private val request: GetimageRequest) : DataFetcher<ByteBuffer> {

    private val disposables = Compositedisposable()

    override fun cleanup() {
        disposables.clear()
    }

    override fun loadData(priority: Priority, callback: DataFetcher.DataCallback<in ByteBuffer>) {
        api.getimage(request)
                .map { it.image.decodeBase64() }
                .subscribe({ callback.onDataReady(ByteBuffer.wrap(it)) }, {
                    if (it is Exception) {
                        callback.onLoadFailed(it)
                    } else {
                        callback.onLoadFailed(MyException(it))
                    }
                })
                .addTo(disposables)
    }

    override fun cancel() {
        disposables.clear()
    }

    override fun getDataClass(): Class<ByteBuffer> {
        return ByteBuffer::class.java
    }

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

}

相关文章

Android性能优化——之控件的优化 前面讲了图像的优化,接下...
前言 上一篇已经讲了如何实现textView中粗字体效果,里面主要...
最近项目重构,涉及到了数据库和文件下载,发现GreenDao这个...
WebView加载页面的两种方式 一、加载网络页面 加载网络页面,...
给APP全局设置字体主要分为两个方面来介绍 一、给原生界面设...
前言 最近UI大牛出了一版新的效果图,按照IOS的效果做的,页...