JNI 學(xué)習(xí)筆記——通過RegisterNatives注冊原生方法

1.概述

在上一次的筆記《JNI學(xué)習(xí)筆記》 中介紹了Native程序與Java程序的互相調(diào)用庸推。其中Java調(diào)用Nativie方法通常的步驟是:

    1. 聲明native方法: private native void sayHello();
    1. 通過javah 生成native程序的頭文件HelloJNI.h
    1. 實(shí)現(xiàn)對應(yīng)的navtive方法
JNIEXPORT void JNICALL Java_HelloJNI_sayHello(JNIEnv *env, jobject thisObj) {
   printf("Hello World!\n");
   return;
}

這種方法每次增加方法時(shí)讲冠, native方法名稱都需要帶上長長的一坨JNIEXPORT void JNICALL Java_HelloJNI_枕赵, 包名很長的話更是不能忍剿吻。除此之外對于Native方法的方法名也不能修改譬猫。

如果你想擺脫這種冗長的規(guī)則拾弃, 不妨嘗試在JNI的JNI_OnLoad()方法中通過RegisterNatives注冊Java需要調(diào)用的Native方法值桩。

2. JavaVM 和 JNIEnv

注冊navtive方法之前我們需要了解JavaVM, JNIEnv:

JavaVMJNIEnv 是JNI提供的結(jié)構(gòu)體.

JavaVM 提供了允許你創(chuàng)建和銷毀JavaVM的"invokation interface"。理論上在每個(gè)進(jìn)程中你可以穿件多個(gè)JavaVM豪椿, 但是Android只允許創(chuàng)造一個(gè)奔坟。

JNIEnv 提供了大部分JNI中的方法。在你的Native方法中的第一個(gè)參數(shù)就是JNIEnv.

JNIEnv 用于線程內(nèi)部存儲搭盾。 因此咳秉, 不能多個(gè)線程共享一個(gè)JNIEnv. 在一段代碼中如果無法獲取JNIEnv, 你可以通過共享JavaVM并調(diào)用GetEnv()方法獲取鸯隅。

3. JNI_OnLoad()方法

當(dāng)Java層代碼中執(zhí)行:

System.loadLibrary("NativeLib"); //NativeLib 為native模塊名稱

Native 中的 JNI_OnLoad(JavaVM *vm, void *reserved) 方法會被調(diào)用澜建。此時(shí)可以注冊對應(yīng)于Java層調(diào)用的navtive方法。

4. JNINativeMethod結(jié)構(gòu)體

typedef struct {
    const char* name;
    const char* signature;
    void*       fnPtr;
} JNINativeMethod;

以上代碼為jni.h中的源碼滋迈, 可見JNINativeMethod包含三個(gè)元素: 方法名霎奢, 方法簽名, native函數(shù)指針饼灿。

該結(jié)構(gòu)體用于描述需要注冊的方法信息幕侠。

5. RegisterNatives方法

jint RegisterNatives(jclass clazz, const JNINativeMethod* methods,
        jint nMethods)

該方法是JNI環(huán)境提供的用于注冊Native方法的方法。

6. 完整實(shí)現(xiàn)

6.1. Java代碼實(shí)現(xiàn)

Java層代碼不需要做任何調(diào)整

public class NativeLib {

    public static native String getNativeString();

    static {
        System.loadLibrary("NativeLib");
    }
    

6.2. C++ 代碼實(shí)現(xiàn)

6.2.1 實(shí)現(xiàn)Native方法

//可以隨意定義方法名
jstring getString() 
{
    JNIEnv *env = NULL;
    g_jvm->AttachCurrentThread(&env, NULL); //g_jvm為JavaVM指針
    
    return env->NewStringUTF("This is Natvie String!");
}

6.2.2 定義JNINativeMethod數(shù)組碍彭, 聲明需要注冊的方法

static JNINativeMethod methods[] = {
        {"getNativeString", "()Ljava/lang/String;", reinterpret_cast<void*>(getString)}
};

其中getNativeString為Java類中定義的Native方法名晤硕。

()Ljava/lang/String; 為方法的簽名, ()表示該方法無參數(shù)庇忌, Ljava/lang/String;表示返回值為Java中的String類型舞箍。具體簽名規(guī)則請參考《JNI學(xué)習(xí)筆記》 中的內(nèi)容。

reinterpret_cast<void*>(getString) 為Native實(shí)現(xiàn)的方法名皆疹。這里強(qiáng)制轉(zhuǎn)換成了函數(shù)指針疏橄。

6.2.3 JNI_OnLoad()方法實(shí)現(xiàn)

JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
    JNIEnv* env;
    if (JNI_OK != vm->GetEnv(reinterpret_cast<void**> (&env),JNI_VERSION_1_4)) {
        LOGW("JNI_OnLoad could not get JNI env");
        return JNI_ERR;
    }

    g_jvm = vm; //用于后面獲取JNIEnv
    jclass clazz = env->FindClass("com/example/myndkproj/NativeLib");  //獲取Java NativeLib類

    //注冊Native方法
    if (env->RegisterNatives(clazz, methods, sizeof(methods)/sizeof((methods)[0])) < 0) {
        LOGW("RegisterNatives error");
        return JNI_ERR;
    }

    return JNI_VERSION_1_4;
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子捎迫,更是在濱河造成了極大的恐慌晃酒,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,348評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件窄绒,死亡現(xiàn)場離奇詭異贝次,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)彰导,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評論 2 385
  • 文/潘曉璐 我一進(jìn)店門蛔翅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人位谋,你說我怎么就攤上這事山析。” “怎么了倔幼?”我有些...
    開封第一講書人閱讀 156,936評論 0 347
  • 文/不壞的土叔 我叫張陵盖腿,是天一觀的道長。 經(jīng)常有香客問我损同,道長,這世上最難降的妖魔是什么鸟款? 我笑而不...
    開封第一講書人閱讀 56,427評論 1 283
  • 正文 為了忘掉前任膏燃,我火速辦了婚禮,結(jié)果婚禮上何什,老公的妹妹穿的比我還像新娘组哩。我一直安慰自己,他們只是感情好处渣,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,467評論 6 385
  • 文/花漫 我一把揭開白布伶贰。 她就那樣靜靜地躺著,像睡著了一般罐栈。 火紅的嫁衣襯著肌膚如雪黍衙。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,785評論 1 290
  • 那天荠诬,我揣著相機(jī)與錄音琅翻,去河邊找鬼。 笑死柑贞,一個(gè)胖子當(dāng)著我的面吹牛方椎,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播钧嘶,決...
    沈念sama閱讀 38,931評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼棠众,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了有决?” 一聲冷哼從身側(cè)響起闸拿,我...
    開封第一講書人閱讀 37,696評論 0 266
  • 序言:老撾萬榮一對情侶失蹤轿亮,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后胸墙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體我注,經(jīng)...
    沈念sama閱讀 44,141評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,483評論 2 327
  • 正文 我和宋清朗相戀三年迟隅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了但骨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,625評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡智袭,死狀恐怖奔缠,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情吼野,我是刑警寧澤校哎,帶...
    沈念sama閱讀 34,291評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站瞳步,受9級特大地震影響闷哆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜单起,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,892評論 3 312
  • 文/蒙蒙 一抱怔、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧嘀倒,春花似錦屈留、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至碳胳,卻和暖如春勇蝙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背固逗。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工浅蚪, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人烫罩。 一個(gè)月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓惜傲,卻偏偏與公主長得像,于是被迫代替她去往敵國和親贝攒。 傳聞我的和親對象是個(gè)殘疾皇子盗誊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,492評論 2 348

推薦閱讀更多精彩內(nèi)容