glide4.11.0封装gfilib优化gif图片加载
Posted 六道对穿肠
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了glide4.11.0封装gfilib优化gif图片加载相关的知识,希望对你有一定的参考价值。
文章目录
需求: 目前项目中加载进度框采用的是一个gif图片, 使用图片加载框架为glide.
Glide 是如何加载 GIF 动图的?
首先需要区分加载的图片类型,即网络请求拿到输入流后,获取输入流的前三个字节,若为 GIF 文件头,则返回图片类型为 GIF。
确认为 GIF 动图后,会构建一个 GIF 的解码器(StandardGifDecoder),它可以从 GIF 动图中读取每一帧的数据并转换成 Bitmap,然后使用 Canvas 将 Bitmap 绘制到 ImageView 上,下一帧则利用 Handler 发送一个延迟消息实现连续播放,所有 Bitmap 绘制完成后又会重新循环,所以就实现了加载 GIF 动图的效果。
未使用gifli加载gif图,使用glide加载gif效果:
- 内存消耗: 80.7
使用giflib加载gif图效果:
- 内存消耗: 40.9
解决方案 : 使用 giflib 库 (gif编解码库c++ ),并提供Java 。使用它要比glide加载GIF效果效果要好,glide加载加载GIF图片CPU占用高,并且内存占用一直在增加。采用JNI调用的方式加载gif图.
具体步骤 :
下载giflib 和 framesequence
- giflib 下载 framesequence其jin依赖于giflib,所以,得下载其源码,地址在 https://android.googlesource.com/platform/external/giflib/+/refs/heads/master 可以看到giflib已经集成到Android源码里面了
或者在这里下载 https://android.googlesource.com/platform/external/giflib/+/android-9.0.0_r16
- framesequence 下载 framesequence是Androidframework中ex里的一个工具包,其源码地址在
https://android.googlesource.com/platform/frameworks/ex/+/android-9.0.0_r16/framesequence/
导入并集成 giflib 和 framesequence
首先把项目转化为c++项目. 然后在cpp目录创建giflib文件夹,将下载的giflib源码拷贝到giflib文件夹下面
如下图:
将无用的文件删除后在使用cmakelist编译
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)
glide的配置gif使用giflib集成
GifDecoder
package com.example.giflibdemo;
import android.graphics.Bitmap;
import android.support.rastermill.FrameSequence;
import android.support.rastermill.FrameSequenceDrawable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.bumptech.glide.load.Options;
import com.bumptech.glide.load.ResourceDecoder;
import com.bumptech.glide.load.engine.Resource;
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
import java.io.IOException;
import java.io.InputStream;
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);
GifGlideModule
package com.example.giflibdemo;
import android.content.Context;
import android.support.rastermill.FrameSequenceDrawable;
import androidx.annotation.NonNull;
import com.bumptech.glide.Glide;
import com.bumptech.glide.GlideBuilder;
import com.bumptech.glide.Registry;
import com.bumptech.glide.annotation.GlideModule;
import com.bumptech.glide.module.AppGlideModule;
import com.bumptech.glide.module.LibraryGlideModule;
import java.io.InputStream;
@GlideModule
public class GifGlideModule extends AppGlideModule
//public class GifGlideModule extends LibraryGlideModule
@Override
public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder)
super.applyOptions(context, builder);
@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()));
// registry.append(Registry.BUCKET_GIF, InputStream.class,
// FrameSequenceDrawable.class, new GifDecoder(glide.getBitmapPool()));
@Override
public boolean isManifestParsingEnabled()
return false;
GifResource
package com.example.giflibdemo;
import android.support.rastermill.FrameSequenceDrawable;
import androidx.annotation.NonNull;
import com.bumptech.glide.load.resource.drawable.DrawableResource;
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();
GlideExtension
package com.example.giflibdemo;
import android.support.rastermill.FrameSequenceDrawable;
import com.bumptech.glide.RequestBuilder;
import com.bumptech.glide.annotation.GlideType;
import com.bumptech.glide.request.RequestOptions;
@com.bumptech.glide.annotation.GlideExtension
public class GlideExtension
private GlideExtension()
final static RequestOptions DECODE_TYPE = RequestOptions
.decodeTypeOf(FrameSequenceDrawable.class)
.lock();
@GlideType(FrameSequenceDrawable.class)
public static RequestBuilder<android.support.rastermill.FrameSequenceDrawable> asGif2(RequestBuilder<FrameSequenceDrawable> requestBuilder)
// RequestBuilder<android.support.rastermill.FrameSequenceDrawable
return requestBuilder.apply(DECODE_TYPE);
开始使用
int gif = R.mipmap.loading_gif;
//String gif = "http://2zhoumu-comic-public-test.oss-cn-hangzhou.aliyuncs.com/cover/comic/gc1100004.gif";
//使用giflib加载
GlideApp.with(this).as(FrameSequenceDrawable.class).load(gif).into(imageView);
//使用glide原生加载
// Glide.with(this).asGif().load(gif).into(imageView);
加载思路
考虑如何使用,一般是给ImageView设置bitmap,但是bitmap存储效率低.故而使用Drawable. ImageView有一个setImageDrawable的方法
思路:
- 先将gif解压成为一帧一帧的数据
- 将数据绘制到drawable上面去
- 最后将drawable设置到ImagView上面去
系统有个BitmapDrawable,但是这里需要自己定义一个GifDrawable用于显示gif图片 这里framesequence 已经帮我们做了.
创建自定义GifDrawable
GifDrawable 需要做的操作:
- 首先Java准备一个Bitmap Bitmap是要Java端初始化出来的 传给C++
- gif 解压出来之后每一帧(Screen) 填充 成Bitmap
- 把Bitmap 绘制到Canvas 利用 canvas.drawBitmap
注意点:
需要让jni创建java对象
glide 使用glidemodule 官方文档
https://bumptech.github.io/glide/doc/configuration.html
其他资料
Bitmap - 称作位图,一般位图的文件格式后缀为bmp,当然编码器也有很多如RGB565、RGB888。作为一种逐像素的显示对象执行效率高,但是缺点也很明显存储效率低。我们理解为一种
存储对象比较好。
Drawable - 作为Android平下通用的图形对象,它可以装载常用格式的图像,比如GIF、PNG、JPG,当然也支持BMP,当然还提供一些高级的可视化对象,比如渐变、图形等。
giflib api 加载方式:
- 一次性读取gif的信息,然后加载
- 使用流的方式读取,自己去解析加载
以上是关于glide4.11.0封装gfilib优化gif图片加载的主要内容,如果未能解决你的问题,请参考以下文章
腾讯总裁刘炽平回应组织优化传闻;美国软件工程师平均薪水最高;GIF动图发明人去世|极客头条