Glide4.0 以后 监听Gif播放完成

在Glide3.0的时候,我们可以通过GifDecoder获取每一帧的播放时长然后相加得到gif的播放时长,即:

  GifDrawable drawable = (GifDrawable) glideDrawable;
 GifDecoder decoder = drawable.getDecoder();
 long duration = 0;
 for (int i = 0; i < drawable.getFrameCount(); i++) {
         duration += decoder.getDelay(i);
}

然后使用handle 发送一个延时消息,或者其它方法,等gif播放完成以后再做相应操作。

或者,通过重写GifDrawable,重写onStop()方法来处理:

  public  class MyGifDrawable extends GifDrawable {

        public MyGifDrawable (GifDrawable other) {
            this(other, other.getFirstFrame(), other.getFrameTransformation());
        }

        @Override
        public void stop() {
            super.stop();

            //GIF播放完成,可以做一些操作
        }
    }

但是到Glide4.0, GifDecoder 被声明为private,去掉了getDecoder()方法,第一种方法如果不使用反射,是无法做到的。

这时我们可以去重写GifDrawable,MyGifDrawable 继承自GifDrawable,然后我们去获GifDrawable里边存储的gif的数据,然后重新初始化一个GifDecoder,使用这个GifDecoder重新new 一个MyGifDrawable ,在MyGifDrawable 的stop方法中监听gif播放完成的时机。

  public  class MyGifDrawable extends GifDrawable {

public MyGifDrawable (Context context, GifDecoder bitmapProvider, Transformation<Bitmap> frameTransformation, int targetFrameWidth, int targetFrameHeight, Bitmap firstFrame) {
            super(context, bitmapProvider, frameTransformation, targetFrameWidth, targetFrameHeight, firstFrame);
        }

        @Override
        public void stop() {
            super.stop();

            //这里之所以要判断callBack是否为null,是因为在RecycleView中当gif划出屏幕,然后再划入屏幕时,callback会为null,

           //在GifDrawable中的onFrameReady()方法,会判断如果callback为null,会直接会调用onstop方法,当gif图在recycleview中,划出//屏幕再划入屏幕时,callback会为null,这是就会出现,当第一帧刚准备好显示出来,就会马上调用onstop()方法,为避免这种情况,在此加入//下方这个判断。

           if (getCallback() != null) {
                     //GIF播放完成,可以做一些操作
            }
        }


    }

可以在Glide的RequestListener中的onResourceReady中拿到glide解析好的gifDrawable,来调用以下方法初始化我们自己定义的GifDrawable

 public static MyGifDrawable initMyGifDrawable(Context context, GifDrawable gifDrawable) {
        GifBitmapProvider provider = new GifBitmapProvider(Glide.get(context).getBitmapPool());
        Transformation transformation = gifDrawable.getFrameTransformation();
        if (transformation == null) {
            transformation = new CenterCrop();
        }
        ByteBuffer byteBuffer = gifDrawable.getBuffer();
        StandardGifDecoder decoder = new StandardGifDecoder(provider);
        decoder.setData(new GifHeaderParser().setData(byteBuffer).parseHeader(),byteBuffer);
        Bitmap bitmap = gifDrawable.getFirstFrame();
        if (bitmap == null) {
            decoder.advance();
            bitmap = decoder.getNextFrame();
        }
        return new MyGifDrawable(context, decoder, transformation, 0, 0, bitmap);
    }

/

上述方法当点击进入大图查看GIF的时候会有一个严重的问题,由于我们使用的MyGifDrawable是从GifDrawable 中的二进制数组初始化得到的,但是Glide返回给我们的这个GifDrawable 我们并没有使用, 使用的是我们自己初始化的MyGifDrawable,所以当点击进入大图以后,如果默认使用的是Glide返回的GifDrawable,由于大图和外边小图的url相同,Glide会使用小图位置缓存的GifDrawable(我们并没有使用这个GifDrawable,使用的是这个GifDrawable里边数据),所以当关闭大图,然后返回的时候,Glide会检测GifDrawable的引用计数,由于我们在外边小图位置并没有使用这个GifDrawable,所以此时GifDrawable的引用计数为1,当关闭大图,引用计数减一,此时引用计数为0,glide会回收掉这个GifDrawable,那么其中的二进制数组也被销毁,MyGifDrawable中的二进制数组已经被回收了,所以在回到以前的界面就会崩溃。

解决方案:

1. 使用下面这个方法。

2. 在上边方法中,取出byteBuffer中的数据,复制到新的数组,再 decoder.setData()。

3.放弃这个方法,使用反射。

4.解决引用计数的问题()

/

当然也可以使用以下方法来通过Glide拿到图片的二进制数组,来初始化MyGifDrawable :

    // target.get() 必须放到子线程中执行,方法中未做处理,所以此方法必须在子线程中执行
    public static MyGifDrawable loadGif(final Context context, final String url, final RequestOptions options) {
        byte[] data = null;
        FutureTarget<byte[]> target = Glide.with(context)
                .as(byte[].class)
                .load(url)
                .apply(options)
                .into(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL);
        try {
            data = target.get();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return initMyGifDrawable(context, data);
    }

    public static MyGifDrawable initMyGifDrawable(Context context, byte[] data) {
        if (data == null) {
            return null;
        }
        GifBitmapProvider provider = new GifBitmapProvider(Glide.get(context).getBitmapPool());
        Transformation transformation = new CenterCrop();
        StandardGifDecoder decoder = new StandardGifDecoder(provider);
        decoder.read(data);
        decoder.advance();
        Bitmap bitmap = decoder.getNextFrame();
        return new MyGifDrawable(context, decoder, transformation, 0, 0, bitmap);
    }

 

最后拿到MyGifDrawable的对象后,可以调用setLoopCount() 来设置循环次数,调用start()方法开始gif的播放

转载于:https://my.oschina.net/tctw/blog/1831883

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值