JNI裏面調用Java,JNI非JAVA線程裏面調用Java方法


           最近在開發android時由於一些功能需要在JNI裏面實現,然後在C++/C裏面調用Java裏面的方法(相當於CallBack之類的),發現在C++/C的線程裏面調用Java裏面的方法的資料非常少,網上的博客也是差不多一樣的(國內的技術博客都是差不多的,甚至連作者都沒有去實現一下),現在做個記錄:

  在C++/C代碼中調用Java的方法,大致的方法就是 :①找到類(FindClass),②找到方法(GetMethodID),③調用(CallVoidMethod   or CallStaticXXMethod),但是有兩種不同的場景

1、C++/C在Java線程中調用JAVA類裏面的方法

               先解釋一下: 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類裏面的方法

JNI在新起的線程中調用JAVA類裏面的方法 解釋一下:就是我新開了一個線程,裏面沒有 JNIEnv和jclass。怎麼辦?有人會說,保存到全局變量去,嗯,確實有道理,但是在新開的線程裏面,就算保存了 JNIEnv和jclass,直接調用也是會拋異常的。其實我的做法也是保存到全局變量中,只不過不是保存他們,而是JavaVM和jobject
代碼:
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;
}

note:用完之後記得
DetachCurrentThread
<span style="font-weight: bold; white-space: pre;">	</span>Ok.先寫到這裏。這樣我們就可以在C++/c裏面隨便調用Java方法了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章