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

最近公司项目需要加载大量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地址

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容