一个简单的例子让我们初步地了解JNI的作用,但是关于JNI中的一些概念还是需要了解清楚,才能够更好的去利用它来实现我们想要做的事情。
那么C++和Java之间的是如何通过JNI来进行互相调用的呢?
我们知道,在Android中,当Java文件被编译成dex文件之后,会由类加载器加载到Dalvik VM(DVM)中,由DVM来进行解释,翻译成机器语言之后,才能由机器来运行。
而对于C/C++来说,其源代码经由Android提供的NDK工具包,可以编译成可执行动态库(即.so文件),之后,Java和C++之间就可以进行通讯了。
那么,在这里,可以想像,Java的Dex字节码和C/C++的so库肯定是同时运行在一个DVM之中,它们是共同使用一个进程空间的,否则,它们怎么彼此沟通呢?
所以在这里,一个关键的中间区域就是Dalvik VM。而对于C/C++,当它们也被加载进DVM之后,由C/C++实现的函数方法等都会被加载在DVM中的函数表中。
如果想要在C/C++中调用函数,它们必须要有个东西能够让其访问到这个虚拟机中的函数表。
而这个东西就是JNIEnv *。
当我们利用javah生成的C/C++的头文件的时候,如下:
JNIEXPORT jstring JNICALL Java_com_lms_jni_HwDemo_printHello
(JNIEnv *e, jobject j)
{
return (**e).NewStringUTF(e,"Hello from T" );
}
我们可以看到这个方法有两个参数,其中第一个就是JNIEnv *,而我们在Java端定义这个方法的时候,是没有参数的,如下:
public native String printHello();
那么这个JNIEnv是干什么用的?
其实从这个参数的名称就可以看到,就是指JNI的运行环境,我觉得它就是对Java虚拟环境的一个引用,在Android中,就是指Dalvik VM。
参考jni.h文件中关于JNIEnv的定义,如下(对于C和C++,它的定义有点不一样):
struct _JNIEnv;
struct _JavaVM;
typedef const struct JNINativeInterface* C_JNIEnv;
#if defined(__cplusplus)
typedef _JNIEnv JNIEnv; //C++中JNIEnv的类型
typedef _JavaVM JavaVM;
#else
typedef const struct JNINativeInterface* JNIEnv; //C中JNIEnv的类型
typedef const struct JNIInvokeInterface* JavaVM;
#endif
在C中,我们可以看到JNIEnv的类型就是JNINativeInterface* ,是一个指针类型,那么在C++中呢,_JNIEnv是什么样的呢?
struct _JNIEnv {
/* do not rename this; it does not seem to be entirely opaque */
const struct JNINativeInterface* functions;
而对于C++来说, _JNIEnv是一个结构体,里面包含了JNINativeInterface*的结构。
所以从这里也可以看到,对于C和C++来说,它们引用JNIEnv中的方法是有一点不一样的。总的来说,JNIEnv,不管是C,还是C++,其实关键都是JNINativeInterface的这个结构。
我们可以简单看一下JNINativeInterface结构的定义,如下:
struct JNINativeInterface {
void* reserved0;
void* reserved1;
void* reserved2;
void* reserved3;
jint (*GetVersion)(JNIEnv *);
jclass (*DefineClass)(JNIEnv*, const char*, jobject, const jbyte*,
jsize);
jclass (*FindClass)(JNIEnv*, const char*);
jmethodID (*FromReflectedMethod)(JNIEnv*, jobject);
jfieldID (*FromReflectedField)(JNIEnv*, jobject);
/* spec doesn't show jboolean parameter */
jobject (*ToReflectedMethod)(JNIEnv*, jclass, jmethodID, jboolean);
可以看到在它其中定义了很多的函数指针,而通过这些定义,JNI层其实就获得了对DVM的引用,通过定义的这些函数指针,可以定位到虚拟机中的 JNI 函数表,从而实现JNI层在DVM中的函数调用。
所以,可以这样理解,其实JNIEnv,就是对DVM运行环境中C/C++函数的一个引用,而也正因为此,当C/C++想要在DVM中调用函数的时候,由于其是在DVM的环境中,所以它们必须通过JNIEnv* 这个参数来获得这些方法,之后才能够使用。
那么这个JNIEnv是什么时候产生的呢?
当Android中第一个Java线程要调用本地的C/C++代码的时候,DVM就会为该线程产生一个JNIEnv*的指针。而每一个线程在和C/C++互相调用的时候,其对应的JNIEnv 也是相互独立。
嗯,结束。
分享到:
相关推荐
Android Studio JNI 的静动态注册开发以及CC++ JNIEnv的理解
这是一个androidstudio环境下的jni的学习,里面包含了基本数据类型转化,引用数据类型转化,json格式数据类型的转化等
本程序是在Eclipse中创建的一个Android Application,该项目中是在JNI中利用OpenGL ES库和OpenCV库进行一副图片的渲染。
Android中调用JNI例子,对应博客http://blog.csdn.net/wwj_748/article/details/28300451
android JNI学习三的最后代码实例
Android中实现JNI的AES加解密源代码,绝对可以运行!
Android 串口读写程序 JNI代码程序
Android中的JNI测试程序 最简单的实现JNI的测试代码,配合我的博客的博文学习
android通过JNI访问硬件LED,包含应用程序APP,JNI代码,和LED驱动程序。
Android NDK JNI 经典实例Android NDK JNI 经典实例Android NDK JNI 经典实例Android NDK JNI 经典实例Android NDK JNI 经典实例Android NDK JNI 经典实例Android NDK JNI 经典实例
在android中使用jni,在jni中调用jni里面的方法
Android JNI 部分学习文档 http://blog.csdn.net/liuhaomatou/article/details/8659088
我的记录android JNI学习一里面最终的实例。
此外,在执行Java类的过程中,如果Java类需要与C组件沟通时,VM就会去载入C组件,然后让Java的函数顺利地调用到C组件的函数。此时,VM扮演着桥梁的角色,让Java与C组件能通过标准的JNI介面而相互沟通。 应用层的...
Android中调用JNI例子.rar,太多无法一一验证是否可用,程序如果跑不起来需要自调,部分代码功能进行参考学习。
android中jni的简单使用示例代码
在jni中获取android 设备的mac地址
JNI学习_Android开发JNI学习_Android开发JNI学习_Android开发
Android使用JNI调用Python so解释器
一个简单的jni demo,意在学习如何在Android Studio中引入jni程序。