NDK--JNI開發(fā)

使用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);

? ? ? ? }

};

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容