【问题标题】:Glide, is it better to use `CustomTarget<Bitmap>()` than `CustomViewTarget<Drawable>` to reduce memory usage?Glide,使用 `CustomTarget<Bitmap>()` 是否比 `CustomViewTarget<Drawable>` 更好地减少内存使用?
【发布时间】:2020-12-24 19:30:05
【问题描述】:

在安卓应用中使用 Glide v4。用例是有一个活动在后台堆栈中有一些片段。 每个 Fragment 将从远程加载一到十个以下的图像。

具有将图像加载到 ImageView 的 kotlin 扩展:

fun ImageView.loadImg(
    imageUrl: String,
    diskCacheStrategy: DiskCacheStrategy = DiskCacheStrategy.AUTOMATIC,
    skipMemoryCache: Boolean = true,
    roundingRadius: Int = 0,
    target: Target<Drawable>? = null,
    requestOptions: RequestOptions = RequestOptions(),
    decodeFormat: DecodeFormat = DecodeFormat.PREFER_RGB_565 
) {
    requestOptions
        .diskCacheStrategy(diskCacheStrategy)
        .format(decodeFormat)
        .apply {
            if (roundingRadius > 0) {
                transform(CenterCrop(), RoundedCorners(roundingRadius))
            }
        }

        Glide.with(this.context)
            .load(imageUrl)
            .apply(requestOptions)
            .skipMemoryCache(skipMemoryCache)
            .apply {
                if (target == null) {
                    into(this@loadImg)
                } else {
                    into(target)
                }
            }
}

片段中的典型调用如下:

imageView.loadImg(
            imageUrl = imageUrl,
            roundingRadius = imageRoundingRadius,
            target = object : CustomViewTarget<ImageView, Drawable>(imageView) {
                override fun onLoadFailed(errorDrawable: Drawable?) {
                   imageView.setImageDrawable(null)
                    visibility = View.GONE
                }
                override fun onResourceCleared(placeholder: Drawable?) {
                    imageView.setImageDrawable(null)
                    visibility = View.GONE
                }
                override fun onResourceReady(resource: Drawable, transition: Transition<in Drawable>?) {
                    imageView.setImageDrawable(resource)
                    visibility = View.VISIBLE
                }
            }
        )

问题是每当一个片段被放入视图并添加到后台堆栈时,分析器中的图形内存显示增加了 50 毫克。除了片段中的图像之外,没有太多其他数据。如果注释掉加载图片好像减少了很多。

不确定这里的代码 loadImage() 是否正确?注意到它在 Glide.with(this.context) 中使用 ImageView 的上下文,也就是 Activity。这是个问题吗? Glide.with(this.context) 和 Glide.with(theFragment) 有什么区别? 什么时候清除Target最好:Glide.with(theFragment).clear(theTarget)?

注意到有一个 CustomTarget(),如果它可以占用图像大小,使用它是否有助于减少内存使用?

目标代码如下:Target&lt;Bitmap&gt;

fun ImageView.loadImgAsBitmap(
    imageUrl: String,
    diskCacheStrategy: DiskCacheStrategy = DiskCacheStrategy.AUTOMATIC,
    skipMemoryCache: Boolean = true,
    roundingRadius: Int = 0,
    target: Target<Bitmap>? = null,
    requestOptions: RequestOptions = RequestOptions(),
    decodeFormat: DecodeFormat = DecodeFormat.PREFER_RGB_565 
) {
    requestOptions
            .diskCacheStrategy(diskCacheStrategy)
            .format(decodeFormat)
            .apply {
                if (roundingRadius > 0) {
                    transform(CenterCrop(), RoundedCorners(roundingRadius))
                }
            }

        Glide.with(this.context)
                .asBitmap()
                .load(imageUrl)
                .apply(requestOptions)
                .skipMemoryCache(skipMemoryCache)
                .apply {
                    if (target == null) {
                        into(this@loadImgAsBitmap)
                    } else {
                        into(target)
                    }
                }
}

和用法是:

imageView.loadImgAsBitmap(imageUrl,
            target = object : CustomTarget<Bitmap>() {
                override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
                    if (resource.height < IMAGE_MIN_SIZE) {// it could check the bitmap size and make use of it
                        imageView.visibility = View.GONE
                        textView.visibility = View.VISIBLE
                    } else {
                        imageView.setImageBitmap(resource)
                    }
                }
                override fun onLoadCleared(placeholder: Drawable?) {
                    imageView.setImageDrawable(null)
                }
            })

这个至少提供位图大小更好,以便 UI 可以使用它。

问题是使用CustomTarget&lt;Bitmap&gt;()Target&lt;Drawable&gt; 更能减少内存使用吗? 如何指定图片大小来替换默认的Target.SIZE_ORIGINA,即is very memory inefficient

【问题讨论】:

    标签: out-of-memory android-glide


    【解决方案1】:

    可能会迟到回答。我一直在研究使用 Glide v4 优化图像的负载,并得到了很好的post。作者提供了详细的解释和建议的解决方案,其中描述的示例之一与问题中提出的用例完全相同。

    综上所述,作者建议不要在每次视图离开屏幕(移至回栈)时调用Glide.with(context).clear(imageView),而是建议使用:

    • RGB_565位图格式(Glide v4默认使用ARGB_8888),条件是图像不包含透明和明显的渐变点。它可以减少多达 50% 的内存消耗。
    • CustomViewTargetCustomTarget 将大小传递给其构造函数或调用 override 以指定所需的位图尺寸,因为CustomTarget 倾向于在未指定大小时加载原始图像大小。而前者CustomViewTarget 总是在至少一个维度已知时根据视图维度加载图像。

    【讨论】:

      猜你喜欢
      • 2012-08-19
      • 2011-10-26
      • 1970-01-01
      • 1970-01-01
      • 2013-05-21
      • 2011-01-17
      • 2014-01-19
      • 2011-09-22
      • 1970-01-01
      相关资源
      最近更新 更多