最近在開發android時由於一些功能需要在JNI裏面實現,然後在C++/C裏面調用Java裏面的方法(相當於CallBack之類的),發現在C++/C的線程裏面調用Java裏面的方法的資料非常少,網上的博客也是差不多一樣的(國內的技術博客都是差不多的,甚至連作者都沒有去實現一下),現在做個記錄:
在C++/C代碼中調用Java的方法,大致的方法就是 :①找到類(FindClass),②找到方法(GetMethodID),③調用(CallVoidMethod or CallStaticXXMethod),但是有兩種不同的場景:
1、C++/C在Java線程中調用JAVA類裏面的方法
JNIEXPORT jint JNICALL Java_com_example_testjni_Hunter_test(JNIEnv *env, jclass obj,jstring str){
return 0;
}
</pre> 這個方法就相當於一個接口,提供給Java調用。這個方法中我們得到了 <span style="background-color: rgb(240, 240, 240);">JNIEnv 和jclass所以調用Java代碼裏面的方法也極其簡單,直接上代碼</span></div><div><span style="background-color: rgb(240, 240, 240);"><span style="white-space:pre"> </span></span><pre name="code" class="cpp">JNIEXPORT jint JNICALL Java_com_example_testjni_Hunter_test(JNIEnv *env, jclass obj,jstring str){
// 注意C++和C代碼中env的寫法。 不要說博主的博客複製都有錯啊!!!!!!!!
// .cpp 文件是C++代碼,博主現在就是C++代碼
// 如果是C代碼,那麼寫法是 jclass test = (*env)->FindClass(env,"com/example/testjni/Hunter");
//因爲有了 JNIEnv和jclass。調用比較方便
//1 . 找到java代碼的 class文件
jclass test = env->FindClass("com/example/testjni/Hunter");// 參數就是java類的路徑加上名字
if(test==0){
// 找不到類,寫錯了??注意包名,類名
return -1;
}
//2 尋找class裏面的方法。。參數①:類名的引用,②準備調用Java類裏面方法的名字,
//③括號裏面表示方法的要傳入的參數類型,現在是空的
// 括號外面 V 表示這個方法的返回值是 void 類型的
jmethodID method1 = env->GetMethodID(test,"helloFromJava","()V");
if(method1==0){
// 找不到類,寫錯了??注意方法的名字
return -1;
}
// 例子 :如果參數是一個 整形的怎麼寫???注意括號裏面的 I
// 就這樣 jmethodID method1 = env->GetMethodID(test,"helloFromJava","(I)V");
// 終於找到了。。。
//3 .調用這個方法,
// 參數說明 ②爲方法的名字,如果有參數記得在後面填上,
env->CallVoidMethod(obj,method1);
// 例子 :如果參數是一個 整形的怎麼寫???
// 就這樣 env->CallVoidMethod(obj,method1,10); // 10就是要傳到Java 方法裏面的參數
return 0;
}
note:注意JNI裏面C++代碼和C代碼的區別2、JNI在新起的線程中調用JAVA類裏面的方法
static JavaVM *gs_jvm = NULL; // 保存起來
static jobject gs_object = NULL; // 保存起來
JNIEXPORT jint JNICALL Java_com_example_testjni_Hunter_test(JNIEnv *env,
jclass obj) {
// 注意了,在第一次進來的時候,我就保存他們了,要快!!!!
env->GetJavaVM(&gs_jvm); //保存到全局變量中JVM
gs_object = env->NewGlobalRef(obj);
return 0;
}
/* 服務器發送過來的消息到達了 */
int frecvMsg_callback() {
// 注意!!我要調用了
JNIEnv *env;
// 獲取當前線程的 env
gs_jvm->AttachCurrentThread((void **) &env, NULL);
// 這個class默認是初始化gs_object時所調用的Java 類
jclass cls = env->GetObjectClass(gs_object);
// 開始對講消息------
jmethodID mid = env->GetMethodID(cls, "startTalkback", "(I)V");
if (mid == NULL) {
return -1;
}
// 調用
env->CallVoidMethod(gs_object, mid, 1);
// 用完之後一定要 DetachCurrentThread 取消關聯,要不然程序退出會有異常
(gs_jvm)->DetachCurrentThread();
return 0;
}
DetachCurrentThread
<span style="font-weight: bold; white-space: pre;"> </span>Ok.先寫到這裏。這樣我們就可以在C++/c裏面隨便調用Java方法了。