美文网首页音视频积累Android生产力
Android使用giflib库高效加载gif图片总结

Android使用giflib库高效加载gif图片总结

作者: 怎么快乐 | 来源:发表于2020-03-25 03:50 被阅读0次

    最近公司项目需要加载大量gif图片,我们项目用的图片加载库是glide,众所周知glide自带加载gif功能,但是真实使用到项目中 glide加载gif会占用大量内存导致应用卡顿,严重的会奔溃。查看glide源码发现glide加载gif图片,使用java解码,所以导致内存增高。想到原来项目中用过的一个加载本地gif的三方库( android-gif-drawable ),人家优化的就很好没有那么卡,就开始研究人家的代码,研究后发现人家这个库性能好的原因是他用giflib来解码gif,但是他这个库只能加载本地图片,而我们项目需要加载网络图片,所以就想把glide和giflib做一个结合,使用glide下载图片,bitmap缓存的功能,解码器替换成giflib,经过一天研究终于成功了,写文章记录一下,也希望其他新手朋友有同样需求的有现成的参考O(∩_∩)O。

    使用giflib需要一点ndk开发的经验,最起码能看懂cmake语法,因为现在android开发ndk都是使用cmalelist。

    ndk部分

    首先需要下载 framesequencegiflib(以上网站需要翻墙,请自备梯子)

    giflib目录如下

    image

    framesequence 项目jin目录如下

    image

    按以下步骤操作

    1. 使用AndroidStudio创建NDK项目。

    2. 把framesequence下的jin文件复制到自己项目的cpp文件夹下(只复制我图片中的.cpp .h文件 多余部分请不要复制),把giflib文件夹复制到cpp目录下。

    3. 在cpp文件夹下新增util文件夹,创建log,math的头文件。(文末会给demo链接,里面有这个两个文件)

    image

    4. 重新写CMackList.txt如下

    cmake_minimum_required(VERSION 3.4.1)
    
    file(GLOB_RECURSE GIF_LIB ${CMAKE_SOURCE_DIR}/giflib/*.*)
    file(GLOB_RECURSE FRAME_SEQUENCE ${CMAKE_SOURCE_DIR}/*.cpp*)
    
    add_library(mygif
            SHARED
            ${FRAME_SEQUENCE}
            ${GIF_LIB})
    
    list(APPEND LIBS
            jnigraphics
            android
            GLESv2
            log
            )
    
    set(LIBS)
    list(APPEND LIBS
            jnigraphics
            android
            GLESv2
            log
            )
    
    target_link_libraries(mygif ${LIBS})
    
    

    最终项目的cpp文件是这样的

    image

    这时候点击Build -> Refresh LInked C++ Projects

    image

    等待项目编译好后,运行项目看是否能跑起来,如果跑起来证明so已生成,关于ndk的部分就结束了,剩下只有java代码了。(●ˇ∀ˇ●)

    java部分

    1. 把framesequence项目中的android文件夹复制到你自己项目的java文件夹下,如图

    image

    2. 项目导入glide(4.+版本),创建一个类 继承 AppGlideModule,使用过glide都知道这个类的用处,可以生成GlideApp,设置缓存大小,缓存路径等功能。我们继承这个类主要的目的是替换glide的gif加载

    
    @GlideModule
    public class GifGlideModule extends AppGlideModule {
    
        @Override
        public void registerComponents(@NonNull Context context,
                                       @NonNull Glide glide, @NonNull Registry registry) {
            super.registerComponents(context, glide, registry);
            registry.append(Registry.BUCKET_GIF, InputStream.class,
                    FrameSequenceDrawable.class, new GifDecoder(glide.getBitmapPool()));
        }
    }
    
    

    这时发现GifDecoder报错,这个文件是需要我们自己编写的,代码如下

    
    public class GifDecoder implements ResourceDecoder<InputStream, FrameSequenceDrawable> {
    
        private BitmapPool bitmapPool;
    
        public GifDecoder(BitmapPool bitmapPool) {
            this.bitmapPool = bitmapPool;
        }
    
        @Override
        public boolean handles(@NonNull InputStream source, @NonNull Options options) throws IOException {
            return true;
        }
    
        @Nullable
        @Override
        public Resource<FrameSequenceDrawable> decode(@NonNull InputStream source, int width, final int height, @NonNull Options options) throws IOException {
            FrameSequence frameSequence = FrameSequence.decodeStream(source);
            FrameSequenceDrawable frameSequenceDrawable = new FrameSequenceDrawable(frameSequence, new FrameSequenceDrawable.BitmapProvider() {
                @Override
                public Bitmap acquireBitmap(int minWidth, int minHeight) {
                    return bitmapPool.get(minWidth, minHeight, Bitmap.Config.ARGB_8888);
                }
    
                @Override
                public void releaseBitmap(Bitmap bitmap) {
                    bitmapPool.put(bitmap);
                }
            });
            return new GifResource(frameSequenceDrawable);
        }
    }
    
    

    GifResource文件也是自己编写的,代码如下

    
    public class GifResource extends DrawableResource<FrameSequenceDrawable> {
    
        public GifResource(FrameSequenceDrawable drawable) {
            super(drawable);
        }
    
        @NonNull
        @Override
        public Class<FrameSequenceDrawable> getResourceClass() {
            return FrameSequenceDrawable.class;
        }
    
        @Override
        public int getSize() {
            return 0;
        }
    
        @Override
        public void recycle() {
            drawable.stop();
            drawable.destroy();
        }
    }
    
    

    到这里 所有的代码都写完,重新编译项目,让glide生成GlideApp

    在代码中使用

    String gif = "gif格式的图片url";
    GlideApp.with(this).as(FrameSequenceDrawable.class).load(gif).into(imageView);
    

    Demo地址

    相关文章

      网友评论

        本文标题:Android使用giflib库高效加载gif图片总结

        本文链接:https://www.haomeiwen.com/subject/yybzyhtx.html