JNI原理分析

一基于開發(fā)Android的C++必備知識

自我感覺Android開發(fā)JNI僅僅是為了調(diào)用c庫完成一些操作,所以僅僅需要了解基礎(chǔ)的c/c++就足夠了,首先jni的本地函數(shù)的必備參數(shù)就是兩個結(jié)構(gòu)體指針,所以最先學(xué)習(xí)結(jié)構(gòu)體指針

#includestruct smile

{

char sna;

char size;

float price;

};

int main(void)

{

struct smile x;

x.sna = 'M';

x.size = 'B';

x.price = 20.5;

printf( "%c, %c, %.1f", x.sna, x.size, x.price );

return 0;}

這是一個典型的結(jié)構(gòu)體定義和調(diào)用的寫法,和Java的區(qū)別是不需要new對象,結(jié)構(gòu)體成員變量的訪問除了可以借助符號".",還可以用"->"訪問,這就需要結(jié)構(gòu)體的指針,后面我們會知道本地函數(shù)會將Java對象的地址傳遞給c,所以jni中都是指針訪問的形式

#include#includestruct smile {

char sna;

float price;

};

int main(void)

{

struct smile x;

struct smile *px;

px = &x;

px->sna = 'R';

px->price = 26.8;

printf( "Sna=[%c], Price=%.1f", x.sna, x.price );

}

上面就是指針訪問的形式,將定義的struct對象指針賦值給*px,就可以操作地址,因?yàn)閖ava和c的對象不通用,所以,他們互相調(diào)用的原理虛擬機(jī)就是通過指針進(jìn)行地址操作,下面就分析jni的調(diào)用過程,當(dāng)我們調(diào)用system.loadlibrary()時,vm就會調(diào)用JNI_OnLoad()函數(shù),這個函數(shù)的源碼地址是/system/lib/libmedia_jni

// #define LOG_NDEBUG 0

#define LOG_TAG "MediaPlayer-JNI"

// ………

jint JNI_OnLoad(JavaVM* vm, void* reserved) {

JNIEnv* env = NULL;

jint result = -1;

if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {

LOGE("ERROR: GetEnv failed\n"); goto bail;

}

assert(env != NULL);

if (register_android_media_MediaPlayer(env) < 0) {

LOGE("ERROR: MediaPlayer native registration failed\n");

goto bail;

}

/* success -- return valid version number */

result = JNI_VERSION_1_4;

bail: return result;

}

此函數(shù)回傳JNI_VERSION_1_4值給VM,于是VM知道了其所使用的JNI版本了。此外, JNI_OnLoad()函數(shù)也做了一些初期的動作,例如指令:

if (register_android_media_MediaPlayer(env) < 0) {

LOGE("ERROR: MediaPlayer native registration failed

\n");

goto bail;

}

就將此*.so的<函數(shù)名稱表>登記到VM里,以便能加快后續(xù)調(diào)用本地函數(shù)之效率,Java類別透過VM而調(diào)用到本地函數(shù)。一般是仰賴VM去尋找*.so里的本地函數(shù)。如果需要連續(xù)調(diào)用很多次,每次都需要尋找一遍,會多花許多時間。此時,將此*.so的<函數(shù)名稱表>登記到VM里。

接下來.so中我們實(shí)現(xiàn)我們的本地函數(shù):

JNIEXPORT jstring JNICALL Java_test_yuan_codelearntest_Utils_JniUtils_test(JNIEnv *env,jobject obj)

{

returnenv -> NewStringUTF("Hello World!");

}

jobject obj表示我們的本地函數(shù)所在的類的對象,JNIEnv *env這個參數(shù)可以理解為虛擬機(jī)指針,因?yàn)樘摂M機(jī)是鏈接Java和c的橋梁,我們可以利用這個指針操作java的性能,比如我們可以拿到對象的class:jclass clazz = (*env)->GetObjectClass(env, obj);這樣就可以做一些反射的操作,比如拿到函數(shù)id:? m_mid = (*env)->GetMethodID(env, clazz, "setV", "(I)V");從C調(diào)用java函數(shù):(*env)->CallVoidMethod(env, thiz, m_mid, sum);等等操作

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

相關(guān)閱讀更多精彩內(nèi)容

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