第一种方式,在加载动态链接库的时候,JVM会调用JNI_OnLoad(JavaVM* jvm, void* reserved)(如果定义了该函数)。第一个参数会传入JavaVM指针。
第二种方式,在native code中调用JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args)可以得到JavaVM指针。
两种情况下,都可以用全局变量,比如JavaVM* g_jvm来保存获得的指针以便在任意上下文中使用。
Android系统是利用第二种方式Invocation interface来创建JVM的。
需要强调的是JNIEnv是跟线程相关的。
在native method中,JNIEnv作为第一个参数传入。那么在JNIEnv不作为参数传入的时候,该如何获得它?
JNI提供了两个函数:
(*jvm)->AttachCurrentThread(jvm, (void**)&env, NULL)
(*jvm)->GetEnv(jvm, (void**)&env, JNI_VERSION_1_2)
两个函数都利用JavaVM接口获得JNIEnv接口,上面已经讲到如何获得JavaVM接口。
JNI规范也说明,可以将获得JNIEnv封装成一个函数。
1
2
3
4
5
6
|
JNIEnv* JNU_GetEnv()
{
JNIEnv* env;
(*g_jvm)->GetEnv(g_jvm, (
void
**)&env, JNI_VERSION_1_2);
return
env;
}
|
Java通过JNI机制调用c/c++写的native程序。c/c++开发的native程序需要遵循一定的JNI规范,下面的例子就是一个JNI函数声明: