Custom Glide ModelLoader para imágenes base64

Tengo imágenes de alguna API SOAP que están codificadas en base64. Para cargarlos directamente con Glide, decidí escribir ModelLoader personalizado.

Versión Glide : 4.3.1

Línea de carga Glide :

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)) } } 

Cargador :

 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 } } 

Stack trace / LogCat :

com.bumptech.glide.Registry $ NoSourceEncoderAvailableException: no se pudo encontrar el codificador fuente para la class de datos: class [B en com.bumptech.glide.Registry.getSourceEncoder (Registry.java:534) en com.bumptech.glide.load.engine. DecodeHelper.getSourceEncoder (DecodeHelper.java:232) en com.bumptech.glide.load.engine.SourceGenerator.cacheData (SourceGenerator.java:74) en com.bumptech.glide.load.engine.SourceGenerator.startNext (SourceGenerator.java: 45) en com.bumptech.glide.load.engine.DecodeJob.runGenerators (DecodeJob.java:298) en com.bumptech.glide.load.engine.DecodeJob.runWrapped (DecodeJob.java:268) en com.bumptech.glide .load.engine.DecodeJob.run (DecodeJob.java:229) en java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1162) en java.util.concurrent.ThreadPoolExecutor $ Worker.run (ThreadPoolExecutor.java:636 ) en java.lang.Thread.run (Thread.java:764) en com.bumptech.glide.load.engine.executor.GlideExecutor $ DefaultThreadFactory $ 1.run (GlideExecutor.java:413)

Creo que me falta algo para que funcione.

Gracias al comentario de https://github.com/bumptech/glide/issues/2677 encontré la solución.

 @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 } } 
  • Manera idiomática de invocar methods a través de la reflexión en Kotlin
  • ¿Cómo encadenar transformaciones en Android al usar datos en vivo?
  • La notificación de respuesta directa comienza una actividad
  • ¿Cómo puedo hacer que kotlin se dé count de que esta function de comparación de BST es recursiva de queue?
  • ¿Puedo inferir el tipo de una propiedad en el delegado?
  • KOTLIN orphanRemoval no funciona
  • Kotlin: asigna el valor de enum a variable sin .value
  • Fragmento en kotlin
  • Trabajando con @Qualifier en las funciones de Kotlin
  • GL_INVALID_OPERATION en glBufferData () en kotlin
  • Kotlin: cuando expresión con retorno tipo de function