1.Glide是什么?

Glide是一个面向Android的快速高效的开源媒体管理和图像加载框架,它将媒体解码、内存和磁盘缓存以及资源池封装到一个简单易用的接口中;

Glide支持获取、解码和显示视频静像、图像和动画GIF。Glide包括一个灵活的API,允许开发人员插入几乎任何网络堆栈。默认情况下,Glide使用自定义的基于HttpUrlConnection的堆栈,但也包括插件到Google的Volley项目或Square的OkHttp库中的实用程序库。

Glide的主要重点是尽可能平滑和快速地滚动任何类型的图像列表,但Glide也适用于几乎任何需要获取、调整大小和显示远程图像的情况;

2.Glide依赖

在app_module下bulid.gradle添加glide依赖

dependencies {  implementation 'com.github.bumptech.glide:glide:4.6.1' annotationProcessor 'com.github.bumptech.glide:compiler:4.6.1' }

3.Glide如何加载gif动画

//默认用glide加载本地或者网络gif图片

Glide.with(Context) .asGif() .load(res或者gif的url链接) .into(ImageView);

3.1解决Glide加载gif非常慢的问题

添加缓存策略提高加载显示速度

RequestOptions options = new RequestOptions() .fitCenter() .diskCacheStrategy(DiskCacheStrategy.DATA); Glide.with(context) .asGif() .load(res) .apply(options) .into(imageView);

为其添加缓存策略,其中缓存策略可以为:DATA及None,None及为不缓存,DATA缓存原型;推荐使用DATA在资源解码前缓存,保证图片不被压缩,此属性会导致第一次加载过慢,我的解决办法是做预加载

Glide3.0和4.0的缓存策略DiskCacheStrategy区别

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 根据原始图片数据和资源编码策略来自动选择磁盘缓存策略。(默认策略)

3.2加载gif第一帧

RequestOptions options = new RequestOptions() .fitCenter() .diskCacheStrategy(DiskCacheStrategy.DATA); Glide.with(context) .asBitmap()        //加载第一帧 .load(res) .apply(options) .into(imageView);

3.3控制播放次数

Glide3.0和4.0的播放gif区别

Glide3.0播放gif

Glide.with(this).load(res或者url).diskCacheStrategy(DiskCacheStrategy.SOURCE).into(new GlideDrawableImageViewTarget(imageView, 1));

Glide4.0播放gif

RequestOptions options = new RequestOptions()
                .fitCenter()
                .skipMemoryCache(true)
                .diskCacheStrategy(DiskCacheStrategy.DATA);

        Glide.with(context)
                .asGif()
                .load(res)
                .apply(options)
                .listener(new RequestListener<GifDrawable>() {
                    @Override
                    public boolean onLoadFailed(GlideException e, Object model, Target<GifDrawable> target, boolean isFirstResource) {
                        return false;
                    }

                    @Override
                    public boolean onResourceReady(GifDrawable resource, Object model, Target<GifDrawable> target, DataSource dataSource, boolean isFirstResource) {
                           //设置只播放一次
                           resource.setLoopCount(1);
                           return false;
                    }
                })
                .into(imageView);
    }

3.5Glide加载Gif动画,切换页面的时候先显示最后一帧再开始播放动画的问题解决方案,设置Glide禁止使用内存缓存即可;

//禁止Glide缓存gif图片,否则会导致每次切换页面会先显示gif图片最后一帧,然后才开始播放动画

RequestOptions options = new RequestOptions() .skipMemoryCache(true);

3.6如何监听Glide播放gif完成

Glide3.0和4.0的播放gif完成监听区别

Glide3.0

Glide.with(this)
                .load("xxxurl")
                .listener(new RequestListener<Integer, GlideDrawable>() {

                    @Override
                    public boolean onException(Exception arg0, Integer arg1,
                            Target<GlideDrawable> arg2, boolean arg3) {
                        return false;
                    }

                    @Override
                    public boolean onResourceReady(GlideDrawable resource,
                            Integer model, Target<GlideDrawable> target,
                            boolean isFromMemoryCache, boolean isFirstResource) {
                        // 计算动画时长
                        GifDrawable drawable = (GifDrawable) resource;
                        GifDecoder decoder = drawable.getDecoder();
                        for (int i = 0; i < drawable.getFrameCount(); i++) {
                            duration += decoder.getDelay(i);
                        }
                        //发送延时消息,通知动画结束
                        handler.sendEmptyMessageDelayed(MESSAGE_SUCCESS,
                                duration);
                        return false;
                    }
                }) //仅仅加载一次gif动画
                .into(new GlideDrawableImageViewTarget(imageview, 1));

Glide4.0

但是在Glide4.0中,没法再直接获取GifDecoder对象了,原因是因为GlideDrawable不再提供这个方法了。
我这里是采用反射的方法获取到GifDecoder变量的,具体代码如下:

Glide.with(FirstActivity.this)
        .asGif()
        .load(file)
        .fitCenter()
        .diskCacheStrategy(DiskCacheStrategy.DATA)
        .listener(new RequestListener<GifDrawable>() {
            @Override
            public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<GifDrawable> target, boolean isFirstResource) {
                return false;
            }

            @Override
            public boolean onResourceReady(final GifDrawable resource, Object model, Target<GifDrawable> target, DataSource dataSource, boolean isFirstResource) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        // 计算动画时长
                        int duration = 0;
                        try {
                            GifDrawable gifDrawable = (GifDrawable) resource;
                            //设置循环播放次数为1次
                            gifDrawable.setLoopCount(1);
                            //GifDecoder decoder = gifDrawable.getDecoder();//4.0开始没有这个方法了
                            Drawable.ConstantState state = gifDrawable.getConstantState();
                            if (state != null) {
                                //不能混淆GifFrameLoader和GifState类
                                Object gifFrameLoader = GlideGifUtil.getValue(state, "frameLoader");
                                if (gifFrameLoader != null) {
                                    Object decoder = GlideGifUtil.getValue(gifFrameLoader, "gifDecoder");
                                    if (decoder != null && decoder instanceof GifDecoder) {
                                        for (int i = 0; i < gifDrawable.getFrameCount(); i++) {
                                            duration += ((GifDecoder) decoder).getDelay(i);
                                        }
                                         //发送延时消息,通知动画结束
                        handler.sendEmptyMessageDelayed(MESSAGE_SUCCESS,
                                duration);
                                    }
                                }
                            }
                        } catch (Throwable e) {
                        }
                    }
                }).start();
                return false;
            }
        })
        .into(mAdImg);

反射工具类

public class GlideGifUtil {
    /**
     * 通过字段名从对象或对象的父类中得到字段的值
     *
     * @param object    对象实例
     * @param fieldName 字段名
     * @return 字段对应的值
     * @throws Exception
     */
    public static Object getValue(Object object, String fieldName) throws Exception {
        if (object == null) {
            return null;
        }
        if (TextUtils.isEmpty(fieldName)) {
            return null;
        }
        Field field = null;
        Class<?> clazz = object.getClass();
        for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
            try {
                field = clazz.getDeclaredField(fieldName);
                field.setAccessible(true);
                return field.get(object);
            } catch (Exception e) {
                //这里甚么都不要做!并且这里的异常必须这样写,不能抛出去。
                //如果这里的异常打印或者往外抛,则就不会执行clazz = clazz.getSuperclass(),最后就不会进入到父类中了
            }
        }
        return null;
    }
}

同时,因为我们采用的是反射,所以别忘了在你的proguard-rules.pro中加上Glide的反混淆规则;

#Glide
-keep class com.bumptech.glide.** {*;}

3.7如何提高一次加载Gif的速度

本地gif第一次提高加载速度,实际项目我采用的在导航页面提前通过glide加载gif图片,让glide控件完成gif图片的缓存,然后首页加载的时候glide加载的是缓存中的gif;

参考:

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

Android使用Glide加载Gif慢 获取gif时间

Glide4.0只播放一次Gif以及监听播放完成的实现方法 - 简书

Gitee 极速下载/glide