需求:
近段时间正好有一个需求,是要实现Gif图只加载播放一次,并且要在Gif播放完毕后回调给系统的需求。
因为Glide 3系列的API与4系列还是有很大差距的,这里我们针对Glide 3.x和Glide 4.x的分别进行实现方案的说明。
解决方案:
在Glide3.x的解决方案:
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));
在Glide3.x的解决方案:
在Glide4.x中,我们没法再直接获取GifDecoder
对象了,原因是因为GlideDrawable
不再提供这个方法了。需要采用反射的方法获取到GifDecoder变量,具体代码如下:
public static void loadOneTimeGif(Context context, Object model, final ImageView imageView, final GifListener gifListener) { Glide.with(context).asGif().load(model).listener(new RequestListener<GifDrawable>() { @Override public boolean onLoadFailed(@Nullable 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) { try { Field gifStateField = GifDrawable.class.getDeclaredField("state"); gifStateField.setAccessible(true); Class gifStateClass = Class.forName("com.bumptech.glide.load.resource.gif.GifDrawable$GifState"); Field gifFrameLoaderField = gifStateClass.getDeclaredField("frameLoader"); gifFrameLoaderField.setAccessible(true); Class gifFrameLoaderClass = Class.forName("com.bumptech.glide.load.resource.gif.GifFrameLoader"); Field gifDecoderField = gifFrameLoaderClass.getDeclaredField("gifDecoder"); gifDecoderField.setAccessible(true); Class gifDecoderClass = Class.forName("com.bumptech.glide.gifdecoder.GifDecoder"); Object gifDecoder = gifDecoderField.get(gifFrameLoaderField.get(gifStateField.get(resource))); Method getDelayMethod = gifDecoderClass.getDeclaredMethod("getDelay", int.class); getDelayMethod.setAccessible(true); //设置只播放一次 resource.setLoopCount(1); //获得总帧数 int count = resource.getFrameCount(); int delay = 0; for (int i = 0; i < count; i++) { //计算每一帧所需要的时间进行累加 delay += (int) getDelayMethod.invoke(gifDecoder, i); } imageView.postDelayed(new Runnable() { @Override public void run() { if (gifListener != null) { gifListener.gifPlayComplete(); } } }, delay); } catch (NoSuchFieldException e) { e.printStackTrace(); }catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } return false; } }).into(imageView); } /** * Gif播放完毕回调 */ public interface GifListener { void gifPlayComplete(); }
同时,因为采用的是反射,所以别忘了proguard-rules.pro
中加上Glide的反混淆规则:
#Glide
-keep class com.bumptech.glide.** {*;}