背景需求
我們需要在JNI的C代碼調用Java代碼。實現原理:使用JNI提供的反射借口來反射得到Java方法,進行調用。
JNI關鍵方法講解。
1. 在同一個類中,調用其他方法
JNIEXPORT void JNICALL Java_cn_itcast_ndkcallback_DataProvider_callmethod1 (JNIEnv * env, jobject obj){ //在c代碼里面調用java代碼里面的方法 // java 反射 //1 . 找到java代碼的 class文件 // jclass (*FindClass)(JNIEnv*, const char*); jclass dpclazz = (*env)->FindClass(env,"cn/itcast/ndkcallback/DataProvider"); if(dpclazz==0){ LOGI("find class error"); return; } LOGI("find class "); //2 尋找class里面的方法 // jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*); jmethodID method1 = (*env)->GetMethodID(env,dpclazz,"helloFromJava","()V"); if(method1==0){ LOGI("find method1 error"); return; } LOGI("find method1 "); //3 .調用這個方法 // void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...); (*env)->CallVoidMethod(env,obj,method1); }
注意: 看紅色的內容,如何獲得呢? 這個是函數的簽名。函數簽名借住命令 javap -p -s(這兩個參數一定要加入)來獲得,放到第二個參數即可。
注意:
1. 要加入上面的參數 -p -s
2. signature后面有時候帶“;”,不要丟掉。 主要要仔細檢查
示例:
void notifyOnStatusReport(int32_t status) { if (curEnv != NULL && curObj != NULL) { jclass clsstring = curEnv->FindClass("com/baidu/tieba/liveSdk/publisher/LiveNativeSender"); jfieldID mUsercommandCallbackEventListnerFieldId = curEnv->GetFieldID(clsstring,"mStatusEventListener","Lcom/baidu/tieba/liveSdk/publisher/OnStatusEventListener;"); jobject mUsercommandCallbackEventListner = curEnv->GetObjectField(curObj,mUsercommandCallbackEventListnerFieldId); jclass onStatusEventListenerClsstring = curEnv->FindClass("com/baidu/tieba/liveSdk/publisher/OnStatusEventListener"); jmethodID onStatusReport = curEnv->GetMethodID(onStatusEventListenerClsstring, "onStatusReport", "(I)V"); curEnv->CallVoidMethod(mUsercommandCallbackEventListner, onStatusReport, status); } }
這樣就可以調用DataProvider中的helloFromJava方法了。
2. 上面的方法是調用的返回值為void的java方法。如果想調用其他類型的。JNI中還提供的許多其他返回類型的方法。
jobject (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, ...); jobject (*CallObjectMethodV)(JNIEnv*, jobject, jmethodID, va_list); jobject (*CallObjectMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jboolean (*CallBooleanMethod)(JNIEnv*, jobject, jmethodID, ...); jboolean (*CallBooleanMethodV)(JNIEnv*, jobject, jmethodID, va_list); jboolean (*CallBooleanMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jbyte (*CallByteMethod)(JNIEnv*, jobject, jmethodID, ...); jbyte (*CallByteMethodV)(JNIEnv*, jobject, jmethodID, va_list); jbyte (*CallByteMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jchar (*CallCharMethod)(JNIEnv*, jobject, jmethodID, ...); jchar (*CallCharMethodV)(JNIEnv*, jobject, jmethodID, va_list); jchar (*CallCharMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jshort (*CallShortMethod)(JNIEnv*, jobject, jmethodID, ...); jshort (*CallShortMethodV)(JNIEnv*, jobject, jmethodID, va_list); jshort (*CallShortMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jint (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...); jint (*CallIntMethodV)(JNIEnv*, jobject, jmethodID, va_list); jint (*CallIntMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jlong (*CallLongMethod)(JNIEnv*, jobject, jmethodID, ...); jlong (*CallLongMethodV)(JNIEnv*, jobject, jmethodID, va_list); jlong (*CallLongMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jfloat (*CallFloatMethod)(JNIEnv*, jobject, jmethodID, ...) __NDK_FPABI__; jfloat (*CallFloatMethodV)(JNIEnv*, jobject, jmethodID, va_list) __NDK_FPABI__; jfloat (*CallFloatMethodA)(JNIEnv*, jobject, jmethodID, jvalue*) __NDK_FPABI__; jdouble (*CallDoubleMethod)(JNIEnv*, jobject, jmethodID, ...) __NDK_FPABI__; jdouble (*CallDoubleMethodV)(JNIEnv*, jobject, jmethodID, va_list) __NDK_FPABI__; jdouble (*CallDoubleMethodA)(JNIEnv*, jobject, jmethodID, jvalue*) __NDK_FPABI__; void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...); void (*CallVoidMethodV)(JNIEnv*, jobject, jmethodID, va_list); void (*CallVoidMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
3. 如果java中的方法是靜態的,就需要調用GetStaticMethodID 和 CallStaticVoidMethod 方法。
JNIEXPORT void JNICALL Java_cn_itcast_ndkcallback_DataProvider_callmethod4 (JNIEnv * env, jobject obj){ //1 . 找到java代碼的 class文件 // jclass (*FindClass)(JNIEnv*, const char*); jclass dpclazz = (*env)->FindClass(env,"cn/itcast/ndkcallback/DataProvider"); if(dpclazz==0){ LOGI("find class error"); return; } LOGI("find class "); //2 尋找class里面的方法 // jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*); // 注意 :如果要尋找的方法是靜態的方法 那就不能直接去獲取methodid //jmethodID method4 = (*env)->GetMethodID(env,dpclazz,"printStaticStr","(Ljava/lang/String;)V"); // jmethodID (*GetStaticMethodID)(JNIEnv*, jclass, const char*, const char*); jmethodID method4 = (*env)->GetStaticMethodID(env,dpclazz,"printStaticStr","(Ljava/lang/String;)V"); if(method4==0){ LOGI("find method4 error"); return; } LOGI("find method4 "); //3.調用一個靜態的java方法 // void (*CallStaticVoidMethod)(JNIEnv*, jclass, jmethodID, ...); (*env)->CallStaticVoidMethod(env,dpclazz,method4,(*env)->NewStringUTF(env,"static haha in c")); }
4. 如果C調用的Java方法不在一個類中。
分析:JNI提供的方法都有兩個參數:(JNIEnv *env , jobject obj)。 env是JNI提供的方法集合。 obj是上線文。下面的例子的obj不是所需要的上下午,所以要重新創建。
//obj DemoActivity JNIEXPORT void JNICALL Java_cn_itcast_ndkcallback_DemoActivity_call_1dp_1method1 (JNIEnv * env, jobject obj){ //在c代碼里面調用java代碼里面的方法 // java 反射 //1 . 找到java代碼的 class文件 // jclass (*FindClass)(JNIEnv*, const char*); jclass dpclazz = (*env)->FindClass(env,"cn/itcast/ndkcallback/DataProvider"); if(dpclazz==0){ LOGI("find class error"); return; } LOGI("find class "); //2 尋找class里面的方法 // jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*); jmethodID method1 = (*env)->GetMethodID(env,dpclazz,"helloFromJava","()V"); if(method1==0){ LOGI("find method1 error"); return; } LOGI("find method1 "); //3 .調用這個方法 // void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...); // jobject (*NewObject)(JNIEnv*, jclass, jmethodID, ...); // jobject (*AllocObject)(JNIEnv*, jclass); jobject dpobj= (*env)->AllocObject(env,dpclazz); (*env)->CallVoidMethod(env,dpobj,method1); }
5. 提示
為了避免4中的內容,我們盡量讓C要調用的Java方法在同一個類中