1、看博客之前,请先了解gif动图编码,自行百度;我的理解是,gif可以看作一系列帧动画,我们加载动图时只要每一帧绘制出来就可以形成gif动图了;
gif大小1.93M
加载之前,内存使用14.95M,空闲8.36M:

glide加载gif,使用21.09M,加载2Mgif使用了6M;

giflib源码加载,使用15.27M,加载2Mgif使用了0.32M;

giflib内存节省比glide强悍20倍
2、首先你要下载源码,拷贝giflib相关文件,文件路径:
\android-6.0.0_r1\external\giflib
这里你只需要拷贝我们需要的文件,

拷贝到我们的项目目录cpp下:

这里文件跟我的不一样,不要紧,我进行了重新命名,待会儿用不到的c文件可以直接删除。
上代码了,代码里都有注释。
/**
* 调用android 源码展示gif
* Q164454216
* Created by xiaoke on 2017/4/27.
*/
public class GifHandler {
//代表C层的地址;
private long gifPoint;
public long getGifPoint() {
return gifPoint;
}
public GifHandler(long gifPoint) {
this.gifPoint = gifPoint;
}
static {
try {
System.loadLibrary("native-lib");
} catch (Exception e) {
Log.e(TAG, "static initializer: "+e.toString());
}
}
// public static native int getWidth(gifPoint);
public static native long loadGif(byte[] path);
public static native int getWidth(long gifHandler);
public static native int getHeight(long gifHandler);
public static native int getNextTime(long gifHandler);
public static native int updateFrame(long gifHandler, Bitmap bitmap);
public static GifHandler load(String path) {
long gifHander = loadGif(path.getBytes());
GifHandler gifHandler = new GifHandler(gifHander);
return gifHandler;
}
}
这里我们建了一个加载gif工具类,相关native方法在这里进行执行。
下面native-lib.cpp相关代码
extern "C" {
/**
* 调用c展示gif动态图片
*/
JNIEXPORT jint JNICALL
Java_com_example_xiaoke_gifplayer_GifHandler_getWidth(JNIEnv *env, jclass type, jlong gifHandler) {
GifFileType *gifFileType = (GifFileType *) gifHandler;
return gifFileType->SWidth;
}
JNIEXPORT jint JNICALL
Java_com_example_xiaoke_gifplayer_GifHandler_getHeight(JNIEnv *env, jclass type, jlong gifHandler) {
GifFileType *gifFileType = (GifFileType *) gifHandler;
return gifFileType->SHeight;
}
JNIEXPORT jint JNICALL
Java_com_example_xiaoke_gifplayer_GifHandler_getNextTime(JNIEnv *env, jclass type,
jlong gifHandler) {
GifFileType *gifFileType = (GifFileType *) gifHandler;
GifBean *gifBean = (GifBean *) gifFileType->UserData;
return gifBean->frame_duration;
}
JNIEXPORT jint JNICALL
Java_com_example_xiaoke_gifplayer_GifHandler_updateFrame(JNIEnv *env, jclass type, jlong gifHandler,
jobject bitmap) {
//强转代表gif的结构体
GifFileType *gifFileType = (GifFileType *) gifHandler;
GifBean *gifBean = (GifBean *) gifFileType->UserData;
AndroidBitmapInfo info;
//代表一副图片的像素数组
void *pixels;
//info赋值
AndroidBitmap_getInfo(env, bitmap, &info);
//锁定bitmap,一副图片是二维数组
AndroidBitmap_lockPixels(env, bitmap, &pixels);
//绘制一帧图片
drawFrame(gifFileType, &info, (int *) pixels, gifBean->current_frame, false);
//当前帧+1;
gifBean->current_frame += 1;
//当绘制到最后一帧
if (gifBean->current_frame >= gifBean->total_frame) {
gifBean->current_frame = 0;
}
AndroidBitmap_unlockPixels(env, bitmap);
return gifBean->frame_duration;
}
//jstring to char*
char* jstringTostring(JNIEnv* env, jbyteArray barr)
{
char* rtn = NULL;
// if ((env)->ExceptionCheck()) {
// return rtn;
// }
// jclass clsstring = env->FindClass("Java/lang/String");
// jstring strencode = env->NewStringUTF("utf-8");
//
// jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
// jbyteArray barr= (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);
jsize alen = env->GetArrayLength(barr);
jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
if (alen > 0)
{
rtn = (char*)malloc(alen + 1);
memcpy(rtn, ba, alen);
rtn[alen] = 0;
}
env->ReleaseByteArrayElements(barr, ba, 0);
return rtn;
}
JNIEXPORT jlong JNICALL
Java_com_example_xiaoke_gifplayer_GifHandler_loadGif(JNIEnv *env, jclass type, jbyteArray path_) {
char *filePath = jstringTostring(env, path_);//javastring转换成char*,文件路径
int err;
GifFileType *gifFileType = DGifOpenFileName(filePath, &err);//调用源码api里方法,打开gif,返回GifFileType实体
//初始化结构体
dGifSlurp(gifFileType);
//实例化bean;
GifBean *gifBean = (GifBean *) malloc((sizeof(GifBean)));
gifBean->frame_duration = 0;
gifBean->current_frame = 0;
gifBean->total_frame = 0;
gifBean->total_time = 0;
//好比一个view打一个tag
gifFileType->UserData = gifBean;
//下一步,给gifbean成员变量赋值,得到当前播放时间的总时长;
int i, j, frame_delay;
//一帧图片
SavedImage *frame;
ExtensionBlock *ext;
for (i = 0; i < gifFileType->ImageCount; i++) {
frame = &gifFileType->SavedImages[i];
for (j = 0; j < frame->ExtensionBlockCount; j++) {
//找到含有延迟时间的代码块
if (frame->ExtensionBlocks[j].Function == GRAPHICS_EXT_FUNC_CODE) {
ext = &(frame->ExtensionBlocks[j]);
}
}
if (ext) {
//延迟时间1-->10ms
frame_delay = 10 * (ext->Bytes[2] << 8 | ext->Bytes[1]);
//得到gif总时间
gifBean->total_time += frame_delay;
}
}
//每一帧时间
gifBean->frame_duration = gifBean->total_time / gifFileType->ImageCount;
//总帧数
gifBean->total_frame = gifFileType->ImageCount;
return (long long) gifFileType;
}
mainActivity,调用
File file=new File(Environment.getExternalStorageDirectory(),"test.gif");
gifHandler =GifHandler.load(file.getAbsolutePath());
//得到gif的width,height,生成Bitmap;
int width=gifHandler.getWidth(gifHandler.getGifPoint());
int height=gifHandler.getHeight(gifHandler.getGifPoint());
bitmap= Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888);
int nextTime= gifHandler.updateFrame(gifHandler.getGifPoint(),bitmap);
handler.sendEmptyMessageDelayed(1,nextTime);
}
private Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
int nextTime=gifHandler.updateFrame(gifHandler.getGifPoint(),bitmap);
handler.sendEmptyMessageDelayed(1,nextTime);
iv_gif.setImageBitmap(bitmap);
}
};
ok,项目结束。如果需要源码,请联系我,现在没时间上传了。