使用JNI與Native code通信
什么事JNI?
JNI是Java native interface的縮寫,它提供了若干api實現(xiàn)了Java和其他語言的通信
1.Java代碼調(diào)用原生方法
2.聲明原生方法
3.加載共享庫
4.實現(xiàn)原生方法
JNI語法與規(guī)范
? ? 數(shù)據(jù)類型
? ? ? ? JNI系統(tǒng)類型:JNIEnv(線程上下文)
? ? ? ? 基本數(shù)據(jù)類型
? ? ? ? 引用類型
? ? ? ? 數(shù)組
動態(tài)庫與靜態(tài)庫的區(qū)別
1.靜態(tài)庫文件比較大,動態(tài)庫文件比較小
2.靜態(tài)庫需要在編譯時被鏈接到目標代碼中,動態(tài)庫需要在運行時被鏈接到代碼中
3.靜態(tài)庫類似于Android中的module,一旦打包apk需要重新編譯
4.動態(tài)庫類似與jar包,打包是不需要重新編譯的。
選?。红o態(tài)庫體積比較大,但是加載速度快,動態(tài)庫體積比較小,加載速度慢,想要以時間換空間使用靜態(tài)庫,以空間換時間使用動態(tài)庫PORT
利用系統(tǒng)源碼加載GIF動圖
1.將系統(tǒng)源碼復制到自己項目中(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.創(chuàng)建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 {
//延時,(數(shù)組來保存)
? ? int *delays;
? ? //記錄渲染的當前索引
? ? int current_frame;
? ? //總幀數(shù)
? ? 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結(jié)構(gòu)體,保存了GIF所有信息
//? ? GifFileType *pGifFileType = DGifOpenFileName(gif_path, &error);
//? ? //初始化
//? ? DGifSlurp(pGifFileType);
////給gifBean分配內(nèi)存
//? ? GifBean *gifBean = (GifBean *) malloc(sizeof(gifBean));
////清理內(nèi)存
//? ? memset(gifBean, 0, sizeof(gifBean));
//? ? gifBean->delays = (int *) malloc(sizeof(int) *pGifFileType->ImageCount);
//? ? memset(gifBean->delays, 0, sizeof(int) *pGifFileType->ImageCount);
//? ? ExtensionBlock *extensionBlock;
//? ? //給結(jié)構(gòu)體賦值
//? ? 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結(jié)構(gòu)體:保存了gif所有信息
? ? GifFileType *pGifFileType = DGifOpenFileName(gif_path, &error);
? ? //初始化
? ? DGifSlurp(pGifFileType);
? ? //給GifBean分配內(nèi)存
? ? GifBean *gifBean = (GifBean *) malloc(sizeof(GifBean));
? ? //清理內(nèi)存
? ? memset(gifBean, 0, sizeof(GifBean));
? ? //給延時時間數(shù)組分配內(nèi)存
? ? gifBean->delays = (int *) malloc(sizeof(int) * pGifFileType->ImageCount);
? ? memset(gifBean->delays, 0, sizeof(int) * pGifFileType->ImageCount);
? ? //清理內(nèi)存
? ? ExtensionBlock *extensionBlock;
? ? //給結(jié)構(gòu)體賦值
? ? 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];
? ? ? ? ? ? //根據(jù)索引值到顏色列表中查找
? ? ? ? ? ? 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);
//? ? //指向像素緩沖區(qū)的指針
//? ? 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);
? ? //指向像素緩沖區(qū)的指針
? ? 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層調(diào)用
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);
? ? ? ? }
};