Android中关于JNI 的学习(一)对于JNIEnv的一些认识
2017-09-20 08:58
477 查看
一个简单的样例让我们初步地了解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++的头文件的时候。例如以下:
我们能够看到这种方法有两个參数。当中第一个就是JNIEnv *。而我们在Java端定义这种方法的时候。是没有參数的,例如以下:
[align=left]那么这个JNIEnv是干什么用的?[/align]
[align=left]事实上从这个參数的名称就能够看到,就是指JNI的执行环境,我认为它就是对Java虚拟环境的一个引用。在Android中。就是指Dalvik VM。[/align]
[align=left]參考jni.h文件里关于JNIEnv的定义,例如以下(对于C和C++。它的定义有点不一样):
[/align]
在C中,我们能够看到JNIEnv的类型就是JNINativeInterface* 。是一个指针类型,那么在C++中呢,_JNIEnv是什么样的呢?
[align=left]而对于C++来说。 _JNIEnv是一个结构体。里面包括了JNINativeInterface*的结构。[/align]
[align=left]所以从这里也能够看到。对于C和C++来说,它们引用JNIEnv中的方法是有一点不一样的。总的来说,JNIEnv。无论是C。还是C++,事实上关键都是JNINativeInterface的这个结构。[/align]
[align=left]我们能够简单看一下JNINativeInterface结构的定义,例如以下:
[/align]
能够看到在它当中定义了非常多的函数指针,而通过这些定义。JNI层事实上就获得了对DVM的引用,通过定义的这些函数指针。能够定位到虚拟机中的 JNI 函数表,从而实现JNI层在DVM中的函数调用。
所以。可以这样理解,事实上JNIEnv,就是对DVM执行环境中C/C++函数的一个引用。而也正由于此,当C/C++想要在DVM中调用函数的时候。由于其是在DVM的环境中,所以它们必须通过JNIEnv* 这个參数来获得这些方法,之后才可以使用。
那么这个JNIEnv是什么时候产生的呢?
当Android中第一个Java线程要调用本地的C/C++代码的时候。DVM就会为该线程产生一个JNIEnv*的指针。
而每个线程在和C/C++互相调用的时候。其相应的JNIEnv 也是相互独立。
嗯。结束。
那么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();
[align=left]那么这个JNIEnv是干什么用的?[/align]
[align=left]事实上从这个參数的名称就能够看到,就是指JNI的执行环境,我认为它就是对Java虚拟环境的一个引用。在Android中。就是指Dalvik VM。[/align]
[align=left]參考jni.h文件里关于JNIEnv的定义,例如以下(对于C和C++。它的定义有点不一样):
[/align]
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;
[align=left]而对于C++来说。 _JNIEnv是一个结构体。里面包括了JNINativeInterface*的结构。[/align]
[align=left]所以从这里也能够看到。对于C和C++来说,它们引用JNIEnv中的方法是有一点不一样的。总的来说,JNIEnv。无论是C。还是C++,事实上关键都是JNINativeInterface的这个结构。[/align]
[align=left]我们能够简单看一下JNINativeInterface结构的定义,例如以下:
[/align]
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中关于JNI 的学习(一)对于JNIEnv的一些认识
- Android中关于JNI 的学习(一)对于JNIEnv的一些认识
- Android中关于JNI 的学习(一)对于JNIEnv的一些认识
- Android中关于JNI 的学习(二)对于JNI方法名,数据类型和方法签名的一些认识
- Android中关于JNI 的学习(二)对于JNI方法名,数据类型和方法签名的一些认识
- Android JNI学习系列1.2—— JNI方法名,数据类型和方法签名的一些认识
- android中关于jni调用java层方法的一些误导和见解
- [Android学习系列11]关于Android数据存储的一些事
- Android中关于JNI 的学习(三)在JNI层访问Java端对象
- [Android学习系列9]关于Fragment的一些事
- Android学习札记24:收集到的一些关于解决Bitmap OOM内存溢出的方法
- Android中关于JNI 的学习(四)简单的例子,温故而知新
- 关于Yii的一些认识和学习
- Android中关于JNI 的学习(三)在JNI层访问Java端对象
- [Android学习系列13]关于Gridview的一些事
- Android中关于矩阵(Matrix)前乘后乘的一些认识
- Android中关于Task的一些认识
- 关于android jni的一些总结_补充中
- Android中关于JNI 的学习(零)简单的例子,简单地入门