最近在开发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方法了。