android app动图优化:源码giflib加载gif动图,性能秒杀glide

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文件

这里文件跟我的不一样,不要紧,我进行了重新命名,待会儿用不到的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,项目结束。如果需要源码,请联系我,现在没时间上传了。