md文件相關(guān)操作語法參考
java之jvm的javap命令
獲取class字節(jié)碼相關(guān)、類信息、方法簽名(javap s xxx.class)
本文包括內(nèi)容
配置或小知識點
AndroidStudio中需要打印C中的日志配置或小知識點
jni方法的各個部分所代表的的含義
本地代碼的注冊多線程相關(guān)
JNI多線程注意事項以及
配置或小知識點
在AndroidStudio中需要打印C中的日志:
android{
defaultConfig {
//新版中其實默認已經(jīng)支持了。只需要使用android/log.h即可打印日志
ndk {
ldLibs = "log" //此配置是指添加ndk的日志支持.實際使用:liblog.so
}
}
}
JNI相關(guān)知識點解釋
示例方法:
//實現(xiàn)Java_com_test01_Test_firstTest方法
JNIEXPORT void JNICALL Java_com_test01_Test_firstTest(JNIEnv *, jobject){
Console::WriteLine(L"第一個Jni小程序");
}
1、jni方法的各個部分所代表的的含義
JNIEXPORT void JNICALL Java_com_test01_Test_firstTest (JNIEnv * env, jobject obj);
JNIEXPORT:在Jni編程中所有本地語言實現(xiàn)Jni接口的方法前面都有一個"JNIEXPORT",這個可以看做是Jni的一個標志,至今為止沒發(fā)現(xiàn)它有什么特殊的用處。void:這個學(xué)過編程的人都知道,當然是方法的返回值了。JNICALL:這個可以理解為Jni 和Call兩個部分,和起來的意思就是 Jni調(diào)用XXX(后面的XXX就是JAVA的方法名)。Java_com_test01_Test_firstTest:這個就是被上一步中被調(diào)用的部分,也就是Java中的native 方法名,這里起名字的方式比較特別,是:包名+類名+方法名。JNIEnv* env:這個env可以看做是Jni接口本身的一個對象,在上一篇中提到的jni.h頭文件中存在著大量被封裝好的函數(shù),這些函數(shù)也是Jni編程中經(jīng)常被使用到的,要想調(diào)用這些函數(shù)就需要使用JNIEnv這個對象。例如:env->GetObjectClass()。(詳情請查看jni.h)jobject obj:剛才在Test類的main方法中有這樣一段代碼:
Test t=new Test();
t.firstTest();
這個jobject需要兩種情況分析。上段代碼中firstTest方法是一個非靜態(tài)方法,在Java中要想調(diào)用它必須先實例化對象,然后再用對象調(diào)用它,那這個時候jobject就可以看做Java類的一個實例化對象,也就是obj就是t。如果firstTest是一個靜態(tài)方法,那么在Java中,它不是屬于一個對象的,而是屬于一個類的,Java中用Test.firstTest()這樣的方式來調(diào)用,這個時候jobject就可以看做是java類的本身,也就是obj就是Test.class。
1、本地方法注冊
本地代碼的注冊方式有兩種:
- 在執(zhí)行本地方法前,在Java代碼里使用語句
System.loadLibrary("foo")加載本地方法所有的鏈接庫;- 在本地方法的實現(xiàn)里,需要用到其他鏈接庫里的本地方法時,第一種方法就不適用了,比如,在本地方法里聲明另一個本地方法
void JNICALL g_impl(JNIEnv *env, jobject self);但它的實現(xiàn)是在另一個鏈接庫里實現(xiàn)的,則需要使用下面的代碼來作為這個方法的實現(xiàn):
//這里某一個本地方法里的代碼,省略了其他部分代碼
JNINativeMethod nm;
nm.name = "g";//需要使用的其他鏈接庫里的本地方法的名字
/* 方法的描述,如返回值,參數(shù)等 */
nm.signature = "()V";
nm.fnPtr = g_impl;//在這里的本地方法的聲明的名字
//注冊g_impl方法
(*env)->RegisterNatives(env, cls, &nm, 1);
方法g_imlp的聲明并不需要遵循JNI的命名規(guī)范,因為這只是調(diào)用時的方法指針,并不需要展開代碼(調(diào)用這個方法時,實際調(diào)用的是另一個鏈接庫里名為g的JNI方法),所有不需要使用JNIEXPORT,但需要遵循JNI的調(diào)用規(guī)范。
多線程之間ENV環(huán)境變量的約束:
在本地方法里寫有關(guān)多線程的代碼時,需要知道下面幾個約束:
(注:JVM可以跨線程共享)
- 一個JNIEnv指針只在與它關(guān)聯(lián)的線程里有效,也就是說,在線程間傳遞JNIEnv指針和在多線程環(huán)境里通過緩存來使用它是不允許和不安全的。JVM在同一個線程里多次調(diào)用同一個本地方法時傳遞的是同一個JNIEnv指針,但在不同的線程里調(diào)用同一個本地方法時傳遞的是不同的JNIEnv指針。
- 本地引用只在創(chuàng)建它的線程里有效,也就是說你不能在線程間傳遞本地引用。因為在多線程的環(huán)境里可能會使用到相同的引用,因此我們需要將本地引用轉(zhuǎn)型為全局引用
在任意線程中獲取env環(huán)境對象:
JavaVM *jvm; /* already set */
f(){
JNIEnv *env;
//建立當前線程的連接。將環(huán)境變量變量關(guān)聯(lián)到當前線程,也就是獲取到當前線程
(*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL);
... /* use env */
//使用完成之后一定要調(diào)用此方法釋放jvm和當前線程的連接
javaVM->DetachCurrentThread();
}