使用JNI与Native code通信
什么事JNI?
JNI是Java native interface的缩写,它提供了若干api实现了Java和其他语言的通信
1.Java代码调用原生方法
2.声明原生方法
3.加载共享库
4.实现原生方法
JNI语法与规范
数据类型
JNI系统类型:JNIEnv(线程上下文)
基本数据类型
引用类型
数组
动态库与静态库的区别
1.静态库文件比较大,动态库文件比较小
2.静态库需要在编译时被链接到目标代码中,动态库需要在运行时被链接到代码中
3.静态库类似于Android中的module,一旦打包apk需要重新编译
4.动态库类似与jar包,打包是不需要重新编译的。
选取:静态库体积比较大,但是加载速度快,动态库体积比较小,加载速度慢,想要以时间换空间使用静态库,以空间换时间使用动态库PORT
利用系统源码加载GIF动图
1.将系统源码复制到自己项目中(dgif_lib.c gif_lib.h gif_lib_private.h gifalloc.c)
2.cmakeLists.txt链接jnigraphics库
target_link_libraries(# Specifies the target library.
native-lib-parent
child
jnigraphics
# Links the target library to the log library
# included in the NDK.
${log-lib})
3.创建GifNativeDecoder链接native层
4.native_lib.cpp代码
#include "gif_lib.h"
#define argb(a, r, g, b) ( ((a) &0xff) <<24 ) | ( ((b) &0xff) <<16 ) | ( ((g) &0xff) <<8 ) | ((r) &0xff)
typedef struct GifBean {
//延时,(数组来保存)
int *delays;
//记录渲染的当前索引
int current_frame;
//总帧数
int total_frames;
};
void drawFrame(GifFileType *pGifFileType, GifBean *gifBean, AndroidBitmapInfo info, void *pixels);
extern "C"
JNIEXPORT jlong JNICALL Java_com_example_mycmake_GifNativeDecoder_loadGifNative(
JNIEnv *env,
jclass clazz, jstring gif_path_) {
// const char *gif_path = env->GetStringUTFChars(gif_path_, 0);
// int error;
// //打开GIF文件,获取gifFileType结构体,保存了GIF所有信息
// GifFileType *pGifFileType = DGifOpenFileName(gif_path, &error);
// //初始化
// DGifSlurp(pGifFileType);
////给gifBean分配内存
// GifBean *gifBean = (GifBean *) malloc(sizeof(gifBean));
////清理内存
// memset(gifBean, 0, sizeof(gifBean));
// gifBean->delays = (int *) malloc(sizeof(int) *pGifFileType->ImageCount);
// memset(gifBean->delays, 0, sizeof(int) *pGifFileType->ImageCount);
// ExtensionBlock *extensionBlock;
// //给结构体赋值
// for (int i = 0; i < pGifFileType->ImageCount; i++) {
// SavedImage image = pGifFileType->SavedImages[i];
// for (int j = 0; j < image.ExtensionBlockCount; j++) {
// if (image.ExtensionBlocks[j].Function == GRAPHICS_EXT_FUNC_CODE) {
// //图形拓展块
// extensionBlock = &image.ExtensionBlocks[j];
// break;
// }
// }
// if (extensionBlock) {
// //获取当前帧的图形控制拓展块中的延迟时间(单位1/100秒:10ms)
// gifBean->delays[i] = (extensionBlock->Bytes[2] << 8 | extensionBlock->Bytes[1]) * 10;
// }
// gifBean->total_frames = pGifFileType->ImageCount;
// pGifFileType->UserData = gifBean;
//
// }
// env->ReleaseStringUTFChars(gif_path_, gif_path);
// return (jlong) (pGifFileType);
const char *gif_path = env->GetStringUTFChars(gif_path_, 0);
int error;
//打开gif文件,获取GifFileType结构体:保存了gif所有信息
GifFileType *pGifFileType = DGifOpenFileName(gif_path, &error);
//初始化
DGifSlurp(pGifFileType);
//给GifBean分配内存
GifBean *gifBean = (GifBean *) malloc(sizeof(GifBean));
//清理内存
memset(gifBean, 0, sizeof(GifBean));
//给延时时间数组分配内存
gifBean->delays = (int *) malloc(sizeof(int) * pGifFileType->ImageCount);
memset(gifBean->delays, 0, sizeof(int) * pGifFileType->ImageCount);
//清理内存
ExtensionBlock *extensionBlock;
//给结构体赋值
for (int i =0; i < pGifFileType->ImageCount; i++) {
//取出每一帧图像
SavedImage frame = pGifFileType->SavedImages[i];
for (int j =0; j < frame.ExtensionBlockCount; j++) {
if (frame.ExtensionBlocks[j].Function ==GRAPHICS_EXT_FUNC_CODE) {
//图形控制拓展块
extensionBlock = &frame.ExtensionBlocks[j];
break;
}
}
if (extensionBlock) {
//获取当前帧的图形控制拓展块中的延时时间(单位1/100 秒:10ms)
//小端模式
//Bytes[1] 低八位
//Bytes[2] 高八位
gifBean->delays[i] = (extensionBlock->Bytes[2] <<8 | extensionBlock->Bytes[1]) *10;
}
}
gifBean->total_frames = pGifFileType->ImageCount;
pGifFileType->UserData = gifBean;
env->ReleaseStringUTFChars(gif_path_, gif_path);
return (jlong) (pGifFileType);
}
/**
* 核心代码* @param pGifFileType
* @param gifBean
* @param info
* @param pixels
*/
void drawFrame(GifFileType *pGifFileType, GifBean *gifBean, AndroidBitmapInfo info, void *pixels) {
SavedImage savedImage = pGifFileType->SavedImages[gifBean->current_frame];
GifImageDesc imageDesc = savedImage.ImageDesc;
ColorMapObject *pColorMapObject = imageDesc.ColorMap;
if (NULL == pColorMapObject) {
pColorMapObject = pGifFileType->SColorMap;
}
//先偏移指针
int *px = (int *) pixels;//图像首地址
px = (int *) ((char *) px + info.stride * imageDesc.Top);
int *line;//每一行的首地址
int pointPixelIndex;//像素点的索引值
GifByteType gifByteType;//颜色索引值
GifColorType colorType;//颜色类型
for (int y = imageDesc.Top; y < imageDesc.Top + imageDesc.Height; ++y) {
line = px;
for (int x = imageDesc.Left; x < imageDesc.Left + imageDesc.Width; ++x) {
pointPixelIndex = (y - imageDesc.Top) * imageDesc.Width + (x - imageDesc.Left);
gifByteType = savedImage.RasterBits[pointPixelIndex];
//根据索引值到颜色列表中查找
if (NULL != pColorMapObject) {
colorType = pColorMapObject->Colors[gifByteType];
//给每行每个像素赋予颜色
line[x] =argb(255, colorType.Red, colorType.Green, colorType.Blue);
}
}
px = (int *) ((char *) px + info.stride);
}
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_example_mycmake_GifNativeDecoder_getWidth(JNIEnv *env,
jobject thiz,
jlong gif_pointer) {
GifFileType *pGifFileType = (GifFileType *)gif_pointer;
return pGifFileType->SWidth;
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_example_mycmake_GifNativeDecoder_getHeight(JNIEnv *env, jobject thiz, jlong gif_pointer) {
GifFileType *pGifFileType = (GifFileType *) gif_pointer;
return pGifFileType->SHeight;
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_example_mycmake_GifNativeDecoder_updateFrame(JNIEnv *env,
jobject thiz,
jobject m_bitmap,
jlong gif_pointer) {
// // TODO: implement updateFrame()
// GifFileType *pGifFileType = (GifFileType *) gif_pointer;
// GifBean *gifBean = (GifBean *) pGifFileType->UserData;
//
// AndroidBitmapInfo info;
// //通过bitmap获取AndroidBitmapInfo
// AndroidBitmap_getInfo(env,m_bitmap,&info);
// //指向像素缓冲区的指针
// void *pixels;
// //锁住bitmap
// AndroidBitmap_lockPixels(env,m_bitmap,&pixels);
// //偏移指针
// //渲染绘制一帧图像
// drawFrame(pGifFileType, gifBean, info, pixels);
// gifBean->current_frame += 1;//渲染完当前帧+1
// if(gifBean->current_frame>=gifBean->total_frames){
// gifBean->current_frame=0;
// }
// AndroidBitmap_unlockPixels(env,m_bitmap);
// return gifBean->delays[gifBean->current_frame];
GifFileType *pGifFileType = (GifFileType *) gif_pointer;
GifBean *gifBean = (GifBean *) pGifFileType->UserData;
AndroidBitmapInfo info;
//通过bitmap获取AndroidBitmapInfo
AndroidBitmap_getInfo(env, m_bitmap, &info);
//指向像素缓冲区的指针
void *pixels;
//锁住bitmap
AndroidBitmap_lockPixels(env, m_bitmap, &pixels);
//偏移指针
//渲染绘制一帧图像
drawFrame(pGifFileType, gifBean, info, pixels);
gifBean->current_frame +=1;//渲染完当前帧+1
if (gifBean->current_frame >= gifBean->total_frames) {
gifBean->current_frame =0;
}
AndroidBitmap_unlockPixels(env, m_bitmap);
return gifBean->delays[gifBean->current_frame];
}
5.Java层调用
class NativeLoadGifextends AsyncTask {
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
//加载到gif文件信息了
//渲染图像delaytime
int nextFrameRenderTime=gifNativeDecoder.updateFrame(mBitmap,gifNativeDecoder.getGifPointer());
mHandler.sendEmptyMessageDelayed(1, nextFrameRenderTime);
}
@Override
protected VoiddoInBackground(Void... voids) {
//加载GIF图像
// File file = new File(Environment.getExternalStorageState(), "demo.gif");
// gifNativeDecoder=GifNativeDecoder.loag(file.getAbsolutePath());
// int width=gifNativeDecoder.getWidth(gifNativeDecoder.getGifPointer());
// int height=gifNativeDecoder.getHeight(gifNativeDecoder.getGifPointer());
// mBitmap=Bitmap.createBitmap(width,height,Bitmap.Config.ARGB_8888);
//加载gif图像
File file =new File( Environment.getExternalStorageDirectory(),"demo.gif");
Log.e("dsdfefefsfse",""+file.exists());
if(file.exists()) {
gifNativeDecoder = GifNativeDecoder.loag(file.getAbsolutePath());
int width =gifNativeDecoder.getWidth(gifNativeDecoder.getGifPointer());
int height =gifNativeDecoder.getHeight(gifNativeDecoder.getGifPointer());
mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
}
return null;
}
}
public void loadGif() {
nativeLoadGif.execute();
}
HandlermHandler =new Handler() {
public void handleMessage(Message msg) {
mImageView.setImageBitmap(mBitmap);
int nextFrameRenderTime =gifNativeDecoder.updateFrame(mBitmap, gifNativeDecoder.getGifPointer());
mHandler.sendEmptyMessageDelayed(1, nextFrameRenderTime);
}
};
网友评论