Android开发——优化Glide加载超大gif图,android选择题题库

本文介绍了如何在Android开发中优化Glide加载超大gif图,通过自定义组件替换Glide的默认行为,实现了在加载失败时回退到原生组件。同时,文章探讨了自定义Transformation解决兼容性问题,以及这种方法的局限性和潜在解决方案。适用于减少性能消耗,解决OOM问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

return EncodeStrategy.SOURCE

}

override fun encode(data: Resource<GifDrawable?>, file: File, options: Options): Boolean {

var success = false

if (data is GifLibDrawableResource) {

val byteBuffer = data.buffer

try {

ByteBuf
ferUtil.toFile(byteBuffer, file)

success = true

} catch (e: IOException) {

e.printStackTrace()

}

// DES: 将 resource 编码成文件

Log.d(TAG, “GifLibEncoder -> $success -> ${file.absolutePath}”)

}

return success

}

}

注册组件,注解注册类继承AppGlideModule并在registerComponents中调用如下fun:

@JvmStatic

fun registerGifLib(glide: Glide, registry: Registry) {

//优先使用gifLib-Gif

val bufferDecoder = GifLibByteBufferDecoder(registry.imageHeaderParsers)

val gifLibTranscoder = GifLibBytesTranscoder()

val bitmapBytesTranscoder = BitmapBytesTranscoder()

val gifTranscoder = GifDrawableBytesTranscoder()

registry.prepend(

Registry.BUCKET_GIF, java.io.InputStream::class.java, GifDrawable::class.java,

GifLibDecoder(registry.imageHeaderParsers, bufferDecoder, glide.arrayPool)

).prepend(

Registry.BUCKET_GIF,

java.nio.ByteBuffer::class.java,

GifDrawable::class.java, bufferDecoder

).prepend(

GifDrawable::class.java, GifLibEncoder()

).register(

Drawable::class.java, ByteArray::class.java,

DrawableBytesTranscoder(

glide.bitmapPool,

bitmapBytesTranscoder,

gifTranscoder,

gifLibTranscoder

)

).register(

GifDrawable::class.java, ByteArray::class.java, gifLibTranscoder

)

}

Registry api说明

  • append(..) 追加到最后,当内部的组件在 handles()返回false或失败时候使用追加组件

  • prepend(..)最佳到前面,当你的组件在失败时候使用原生提供组件

  • replace(..)替换组件

Result


验证组件是否注册成功

IGlideModule.with(view).load(url)

.placeholder(R.color.colorAccent)

.listener(object : RequestListener {

override fun onResourceReady(

resource: Drawable?, model: Any?,

target: Target?, dataSource: DataSource?, isFirstResource: Boolean

): Boolean {

if (resource is pl.droidsonroids.gif.GifDrawable) {

Log.d(“TAG”, “giflib的 Gifdrawable”)

} else if (resource is com.bumptech.glide.load.resource.gif.GifDrawable) {

Log.d(“TAG”, “glide的 Gifdrawable”)

}

return false

}

override fun onLoadFailed(

e: GlideException?, model: Any?,

target: Target?, isFirstResource: Boolean

): Boolean = false

})

.into(view)

log: com.example.mydemo D/TAG: giflib的 Gifdrawable

缺陷


这样做看起来侵入性很低的替换了Glide的gif支持,并且还可以兼容giflib出错后使用原生组件,那么缺点呢?缺点也是非常头疼,通常我们会对一些图片加载需求做一些圆角或者圆形等等处理。glide自己的GifDrawable支持的很好,几乎所有的BitmapTransformation都支持,而我们的缺失效了,究其原因是源码中所有transform设置最终调用到如下:

class BaseRequestOptions…

@NonNull

T transform(@NonNull Transformation transformation, boolean isRequired) {

…省略

DrawableTransformation drawableTransformation =

new DrawableTransformation(transformation, isRequired);

transform(Bitmap.class, transformation, isRequired);

transform(Drawable.class, drawableTransformation, isRequired);

transform(BitmapDrawable.class, drawableTransformation.asBitmapDrawable(), isRequired);

//对gifdrawble的 Transformation 支持缘由

transform(GifDrawable.class, new GifDrawableTransformation(transformation), isRequired);

return selfOrThrowIfLocked();

}

}

由于源码已经固定了次转换注入口,除非我们自己修改源码编译或者asm手段。如何解决呢?先依旧照猫画虎GifLibDrawableTransformation然后实现

class GifLibDrawableTransformation(wrapped: Transformation) : Transformation {

private val wrapped: Transformation = Preconditions.checkNotNull(wrapped)

override fun transform(

context: Context, resource: Resource<GifDrawable?>, outWidth: Int, outHeight: Int

): Resource<GifDrawable?> {

val drawable = resource.get()

drawable.transform = object : Transform {

private val mDstRectF = RectF()

override fun onBoundsChange(rct: Rect) = mDstRectF.set(rct)

override fun onDraw(canvas: Canvas, paint: Paint, bitmap: Bitmap) {

val bitmapPool = Glide.get(context).bitmapPool

val bitmapResource: Resource = BitmapResource(bitmap, bitmapPool)

val transformed = wrapped.transform(context, bitmapResource, outWidth, outHeight)

val transformedFrame = transformed.get()

canvas.drawBitmap(transformedFrame, null, mDstRectF, paint)

}

}

return resource

}

override fun equals(o: Any?): Boolean {

if (o is GifLibDrawableTransformation) {

return wrapped == o.wrapped

}

return false

}

override fun hashCode(): Int {

return wrapped.hashCode()

}

override fun updateDiskCacheKey(messageDigest: MessageDigest) {

wrapped.updateDiskCacheKey(messageDigest)

}

}

//每次调用 transform 时候注入下

val circleCrop = CircleCrop()

IGlideModule.with(this)

.load(“http://tva2.sinaimg.cn/large/005CjUdnly1g6lwmq0fijg30rs0zu4qp.gif”)

.transform(GifDrawable::class.java, GifLibDrawableTransformation(circleCrop))

.transform(circleCrop)

.into(iv_2)

缺陷攻克了?其实还没有完美解决,一来这样的书写方式不是很方便,二来目前对ScaleType.CENTER_CROP等支持还是有问题,如果你有更好的建议或者可以修复请提交pr.

总结


glide已经非常优秀了,如果是仅仅少量使用gif完全可以胜任了,而且随着android版和硬件的升级,这些性能问题越来越少,但是如果你发现项目中因为gif的使用导致oom的问题较多可以尝试次优化,另外也可以降低手机发热耗电问题。生命不息折腾不止啊。

推荐:


从Glide源码解读到手写图片加载框架

如何从打造一款可商用的图片加载框架?

手写Glide图片加载框架,让你离架构师的距离更近一步

最后


droid版和硬件的升级,这些性能问题越来越少,但是如果你发现项目中因为gif的使用导致oom的问题较多可以尝试次优化,另外也可以降低手机发热耗电问题。生命不息折腾不止啊。

推荐:


从Glide源码解读到手写图片加载框架

如何从打造一款可商用的图片加载框架?

手写Glide图片加载框架,让你离架构师的距离更近一步

最后


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值