Android 进阶5:Glide4.0源码分析

本文详细介绍了Glide4.0的使用,包括自定义动画、加载圆角图片、缓存策略和网络请求方式。讨论了Glide的生命周期,并深入源码分析了Glide的加载流程,包括请求构造、缓存机制和数据加载。最后,探讨了Glide在处理常见需求如图片更新和尺寸定制等方面的应用。
摘要由CSDN通过智能技术生成

这篇博客其实准备了很久,从Glide的各种使用到Glide的源码分析,Glide的源码很复杂,个人感觉,比LeakCanary,Eventbus等框架源码复杂很多,网上说别Picasso源码复杂,以后再看Picasso的源码吧。

本片博客打算分为三个部分

  1. Glide的使用以及原理
  2. Glide的源码分析
  3. Glide的生命周期

1: Glide的使用

其实关于Glide 的使用,网上有很多,基本都是大同小异,在此不再陈述,这里说一些Glide的比较生疏的用法;

自定义添加动画

当我们第一次加载动画的时候:

    private void glideAddAnimation() {
        Glide.with(this).load(imageUrl).transition(GenericTransitionOptions.with(R.anim.my_anim)).into(imageView);
    }

除了GenericTransitionOptions之外,还有BitmapTransitionOptions和DrawableTransitionOptions,三个的区别不再赘述;R.anim.my_anim也就是我们自己自定义的动画。

上述代码当第一次运行的时候,你会发现挺好的,但是当你第二次运行的时候(相同URL),没有动画过渡;因为上述动画仅仅针对第一次从网络加载图片有效,第二次从缓存获取图片的过渡动画需要另外设置。

        Glide.with(this).load(imageUrl)
                .transition(GenericTransitionOptions.with(R.anim.my_anim)).listener(
                new RequestListener<Drawable>() {
                    @Override
                    public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target,
                            boolean isFirstResource) {
                        return false;
                    }


                    @Override
                    public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target,
                            DataSource dataSource,
                            boolean isFirstResource) {
                        if (dataSource == DataSource.MEMORY_CACHE) {
                            imageView.startAnimation(
                                    AnimationUtils.loadAnimation(getApplicationContext(), R.anim.my_anim));
                        }
                        return false;
                    }
                }).into(imageView);

添加Listener监听,当dataSource代表数据来源,等于MEMORY_CACHE(内存缓存)中获取时,添加动画。

给图片添加动画比较消耗性能,甚至比解码原图资源消耗的都大,所以为了提升性能,请在使用 Glide 向 ListView , GridView, 或 RecyclerView 加载图片时考虑避免使用动画。这是官方的原话。

加载圆角图片

在说圆角图片之前,先说一下,,Glide是支持圆形图片的:

    private void glideCircle() {
        Glide.with(this).load(imageUrl).apply(RequestOptions.circleCropTransform()).into(imageView);
    }

关于圆角图片就需要自定义BitmapTransformation了,代码如下:


/**
 * 圆角图片
 * Created by ${liumengqiang} on 2018/10/9.
 */

public class SecondRoundTransform extends BitmapTransformation {

    private float radius = 10;
    @Override
    protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) {
        //转化后的Bitmap(centerCrop)
        Bitmap centerCropBitmap = TransformationUtils.centerCrop(pool, toTransform, outWidth, outHeight);

        //从BitmapPool(可以理解为Bitmap池)获取一份Bitmap
        Bitmap roundBitmap = pool.get(outWidth, outHeight, Bitmap.Config.ARGB_8888);
        //创建画布,在RoundBitmap写入数据
        Canvas canvas = new Canvas(roundBitmap);
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setShader(new BitmapShader(centerCropBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
        RectF rectF = new RectF(0, 0, centerCropBitmap.getWidth(), centerCropBitmap.getHeight());
        //圆角
        canvas.drawRoundRect(rectF, radius, radius, paint);

        return roundBitmap;
    }

    @Override
    public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {

    }
}
    private void glideRound() {
        Glide.with(this).load(imageUrl).apply(RequestOptions.bitmapTransform(new SecondRoundTransform()))
                .into(imageView);
    }

在上述自定义BitmapTransformation中,为了防止频繁创建Bitmap造成内存抖动,所以是从BitmapPool中获取Bitmap对象。
官方自定BitmapTransformation 文档:https://github.com/bumptech/glide/wiki/Transformations

缓存策略

关于缓存策略,3.0和4.0差别还是比较大的

Glide3.0

			DiskCacheStrategy.NONE:不缓存
			DiskCacheStrategy.SOURCE:之缓存原图
			DiskCacheStrategy.RESULT:只缓存最终要显示的图片(默认选项; Picasso默认缓存原图)
			DiskCacheStrategy.ALL:缓存所有版本的图片

Glide4.0

			DiskCacheStrategy.ALL 使用DATA和RESOURCE缓存远程数据,仅使用RESOURCE来缓存本地数据。
			DiskCacheStrategy.NONE 不使用磁盘缓存
			DiskCacheStrategy.DATA 在资源解码前就将原始数据写入磁盘缓存
			DiskCacheStrategy.RESOURCE 在资源解码后将数据写入磁盘缓存,即经过缩放等转换后的图片资源。
			DiskCacheStrategy.AUTOMATIC 根据原始图片数据和资源编码策略来自动选择磁盘缓存策略。(默认策略)

关于4.0的默认策略官方是这样说的:
默认的策略叫做 AUTOMATIC ,它会尝试对本地和远程图片使用最佳的策略。当你加载远程数据(比如,从URL下载)时,AUTOMATIC 策略仅会存储未被你的加载过程修改过(比如,变换,裁剪–译者注)的原始数据,因为下载远程数据相比调整磁盘上已经存在的数据要昂贵得多。对于本地数据,AUTOMATIC 策略则会仅存储变换过的缩略图,因为即使你需要再次生成另一个尺寸或类型的图片,取回原始数据也很容易。

Glide加载一张新图片时候会检查多级的缓存:

  1. 活动资源(ActivityResource):现在是否有另一个ImageView在显示此图片(宽高也一致)
  2. 内存资源(MemoryCache):图片是否存在在内存中
  3. 资源类型(Rource):图片是否曾被解码之后写入过磁盘缓存
  4. 数据来源(Data):原始数据图片是否写入过文件缓存

第一步和第二步检查都是针对于内存的,如果有就直接返回图片。后两步是发生在磁盘上的,需要异步处理。

每个图片都对应一个Key,这个Key的生成参数:图片路径,Transformtion,Options,请求数据类型等参数。
这些参数经过哈希处理之后就生成一个单独的Key。

Glide默认网络请求方式

Glide默认的网络请求实现是:HttpUrlConnection;
添加implementation 'com.github.bumptech.glide:okhttp3-integration:4.3.1’之后默认的加载数据使用时OkHttp。
Glide也支持Volley加载数据,但是其性能要低于OKHttp。

Glide常见需求
  1. 路径不变,但是服务器的图片变了
  2. 为了保证图片安全,图片带token加载数据(比如七牛云图片)
  3. 请求自定义尺寸图片

对于需求1,该问题的产生是由于Glide的缓存机制,Key缓存是根据图片路径以及其它的一些参数决定的,造成的后果就是请求的永远是缓存中的老图片,有同学会说跳过磁盘缓存就行了,这样确实行,Glide的强大之处就在于缓存机制。再次我们提供的思路是在Key上下功夫,思路就是:定期刷新缓存策略或者是key添加标记(例如version版本号)。官网:https://muyangmin.github.io/glide-docs-cn/doc/caching.html

需求2是常见的需求,但是本身项目中没有遇到,所以没有发言权,附上解决方案:https://blog.csdn.net/wangdaqi77/article/details/72819097。
至于这个解决方案原理我们下文讲到。

需求3的场景就是:请求一定尺寸大小的图片。官方解决方案:https://github.com/bumptech/glide/wiki/Do

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值