Zane'Blog

JNI和NDK编程-JNI调用Java方法的流程

举起酒杯庆祝 大肆谈论那惹人怜的和平世界

JNI调用Java方法的流程是先通过类名找到类,然后再根据方法名找到方法的id,最后就可以调用这个方法了。如果是调用Java中的非静态方法,那么需要构造出类的对象后才能调用它。下面的例子演示了如何在JNI中调用Java的静态方法,至于调用非静态方法只是多了一些构造对象的过程,这里就不再介绍了。

首先需要在Java中定义一个静态方法供JNI调用,如下所示:

1
2
3
public static void methodCalledByJni(String msgFromJni) {
Log.d("---->", "methodCalledByJni,msg: " + msgFromJni);
}

如图所示:

这里写图片描述

然后在JNI中调用上面定义的静态方法:(必须放在调用方法前面,不然会提示找不到此方法,请熟悉C代码的调用与被调用的语法规则)

1
2
3
4
5
6
7
8
9
10
11
12
13
void callJavaMethod(JNIEnv *env, jobject thiz) {
jclass clazz = (*env)->FindClass(env,"io/github/zane/ndkdevdemo/MainActivity");
if(clazz == NULL) {
printf("find class MainActivity error!");
return;
}
jmethodID id = (*env)->GetStaticMethodID(env, clazz, "methodCalledByJni", "(Ljava/lang/String;)V");
if(id == NULL) {
printf("find method methodCalledByJni error!");
}
jstring msg = (*env)->NewStringUTF(env, "msg send by callJavaMethod in test.c!");
(*env)->CallStaticVoidMethod(env, clazz, id, msg);
}

从callJavaMethod的实现可以看出,程序首先根据类名io/github/zane/ndkdevdemo/MainActivity找到类,然后在根据方法名methodCalledByJni找到方法,其中(Ljava/lang/String;)V是methodCalledByJni方法的签名,接着再调用JNIEnv对象的CallStaticVoidMethod方法来完成最终的调用过程。

最后在Java_io_github_zane_ndkdevdemo_JniTest_get方法中调用callJavaMethod方法,如下所示:

1
2
3
4
5
JNIEXPORT jstring JNICALL Java_io_github_zane_ndkdevdemo_JniTest_get (JNIEnv *env, jobject thiz) {
printf("invoke get from C\n");
callJavaMethod(env, thiz);
return (*env)->NewStringUTF(env, "Hello from Zane ouba1 !");
}

如图所示:

这里写图片描述

由于MainActivity会调用JNI中的Java_io_github_zane_ndkdevdemo_JniTest_get方法,Java_io_github_zane_ndkdevdemo_JniTest_get方法又会调用callJavaMethod方法,而callJavaMethod方法又会反过来调用MainActivity的methodCalledByJni方法,这样一来就完成了一次从Java调用JNI然后再从JNI中调用Java方法的过程。先ndk-build后,再安装运行程序,可以看到如下日志,这说明程序已经成功地从JNI中调用了Java中的methodCalledByJni方法。

1
07-04 15:58:17.056 441-441/io.github.zane.ndkdevdemo D/---->: methodCalledByJni,msg: msg send by callJavaMethod in test.c!
坚持原创技术分享,您的支持将鼓励我继续创作!