从本地或远程加载的 Glide ModelLoader

Glide ModelLoader that loads either from local or remote

我有一个自定义 Glide 模型来计算图像的中心裁剪。相同的模型用于从服务器和本地存储获取图像。

模型界面如下:

interface CenterCropImageInformation {
    fun getCenterCropUri(context: Context, @Px width: Int, @Px height: Int): Uri
}

这是从 BaseGlideUrlLoader:

扩展而来的模型加载器
class CenterCropImageInformationLoader private constructor(
    context: Context,
    concreteLoader: ModelLoader<GlideUrl, InputStream>,
    modelCache: ModelCache<CenterCropImageInformation, GlideUrl>?
) : BaseGlideUrlLoader<CenterCropImageInformation>(concreteLoader, modelCache) {
    private val applicationContext: Context = context.applicationContext

    override fun getUrl(
        model: CenterCropImageInformation, width: Int,
        height: Int, options: Options
    ): String {
        return model.getCenterCropUri(applicationContext, width, height).toString()
    }

    override fun handles(centerCropImageInformation: CenterCropImageInformation): Boolean {
        return true
    }

    /**
     * The default factory for [CenterCropImageInformation]s.
     */
    class Factory(
        private val applicationContext: Context,
        private val modelCache: ModelCache<CenterCropImageInformation, GlideUrl>?
    ) : ModelLoaderFactory<CenterCropImageInformation, InputStream> {

        override fun build(
            multiFactory: MultiModelLoaderFactory
        ): ModelLoader<CenterCropImageInformation, InputStream> {
            val modelLoader = multiFactory.build(GlideUrl::class.java, InputStream::class.java)
            return CenterCropImageInformationLoader(applicationContext, modelLoader, modelCache)
        }

        override fun teardown() {}
    }
}

这适用于 http/https 方案的图像,但不适用于 file 方案 - 用于从本地设备存储加载图像的方案。

我查看了 Glide 的源代码,最接近的听起来像是一个选项的 ModelLoader 是 UriLoader,但问题是那个不支持自定义模型。只支持Uri.

最佳解决方案是使用与 Glide 捆绑在一起的预先存在的 ModelLoader,但除非我错过了它,否则我找不到任何适合我需要的东西。如果真是这样,我该如何实现这样的ModelLoader?

看完Glide's ModelLoaders tutorial就明白了。关键是将加载委托给知道如何处理 filehttp/https 方案的 ModelLoader。

我要做的是直接实现 ModelLoader 接口而不是扩展 BaseGlideUrlLoader。我们已经知道 Glide 的内置 UriLoader 可以处理 filehttp/https 方案,所以我们委托给它。现在要获取 UriLoader 的实例,我们使用传递给我们工厂的 build 方法的 MultiModelLoaderFactory 。默认的 Glide 配置为 Uri + InputStream 对注册 UriLoader

class CenterCropImageInformationLoader(
        private val modelLoader: ModelLoader<Uri, InputStream>,
        private val modelCache: ModelCache< CenterCropImageInformation, Uri>
    ) : ModelLoader<CenterCropImageInformation, InputStream> {
        override fun buildLoadData(
            model: CenterCropImageInformation,
            width: Int,
            height: Int,
            options: Options
        ): ModelLoader.LoadData<InputStream>? {
            val uri: Uri = modelCache.get(model, width, height) ?: model.getUri(model, width, height)
            modelCache.put(model, width, height, uri)
            return modelLoader.buildLoadData(uri, width, height, options)
        }

    override fun handles(model: CenterCropImageInformation): Boolean = true

    class Factory(
        private val applicationContext: Context,
        private val modelCache: ModelCache<CenterCropImageInformation, Uri>
    ) : ModelLoaderFactory<CenterCropImageInformation, InputStream> {

         override fun build(
             multiFactory: MultiModelLoaderFactory
         ): ModelLoader<CenterCropImageInformation, InputStream> {
             val modelLoader = multiFactory.build(Uri::class.java, InputStream::class.java)
             return CenterCropImageInformationLoader(applicationContext, modelLoader, modelCache)
         }

         override fun teardown() {}
     }
}

如我们所见,我们不再扩展 BaseGlideUrlLoader。相反,我们实现了 ModelLoader 接口,在 buildLoadData() 实现中,我们尝试从缓存中获取 URI(这类似于 BaseGlideUrlLoader 所做的),然后我们调用 buildLoadData()我们传递给构造函数的 ModelLoader 恰好是 UriLoader 的一个实例,正如我之前提到的,感谢 MultiModelLoaderFactory.

令人惊讶的是,这种类型的 ModelLoader 不是 Glide 内置模型加载器的一部分。