title: Custom Glide ModelLoader for base64 images
body: <p>I have images from some SOAP API that are encoded in base64. To load them directly with Glide I decided to wrote custom ModelLoader.</p>
  
  <p><strong>Glide Version</strong>: 4.3.1</p>
  
  <p><strong>Glide load line</strong>:</p>
  
  <pre><code>GlideApp.with(activity)
          .load(Data().apply { code = licensePlateData.licensePlateImgId })
          .into(view.imageLicense)
  </code></pre>
  
  <p><strong>GlideModule</strong>:</p>
  
  <pre><code>@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))
      }
  }
  </code></pre>
  
  <p><strong>Loader</strong>:</p>
  
  <pre><code>class MyImageLoaderFactory(private val api: Api) : ModelLoaderFactory&lt;Data, ByteArray&gt; {
  
      override fun teardown() {
  
      }
  
      override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader&lt;Data, ByteArray&gt; {
          return MyImageLoader(api)
      }
  }
  
  class MyImageLoader(private val api: Api) : ModelLoader&lt;Data, ByteArray&gt; {
  
      override fun buildLoadData(model: Data, width: Int, height: Int, options: Options): ModelLoader.LoadData&lt;ByteArray&gt; {
          val key = "code:${model.code};width:$width;height:$height"
          return ModelLoader.LoadData&lt;ByteArray&gt;(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&lt;ByteArray&gt; {
  
      private val disposables = CompositeDisposable()
  
      override fun cleanup() {
          disposables.clear()
      }
  
      override fun loadData(priority: Priority, callback: DataFetcher.DataCallback&lt;in ByteArray&gt;) {
          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&lt;ByteArray&gt; {
          return ByteArray::class.java
      }
  
      override fun getDataSource(): DataSource {
          return DataSource.REMOTE
      }
  
  }
  </code></pre>
  
  <p><strong>Stack trace / LogCat</strong>:</p>
  
  <pre><code>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)
  </code></pre>
  
  <p>I think that I'm missing something to make it work. </p>