JNI实战全面解析分类:android2014-11-0109:058083人阅读评论(2)收藏举报目录(?)[+]简介项目决定移植一款C++开源项目到Android平台,开始对JNI深入研究。JNI是什么?JNI(JavaNativeInterface)意为JAVA本地调用,它允许Java代码和其他语言写的代码进行交互,简单的说,一种在Java虚拟机控制下执行代码的标准机制。NDK是什么?AndroidNDK(NativeDevelopmentKit)是一套工具集合,允许你用像C/C++语言那样实现应用程序的一部分。为什么要用NDK?1、安全性,java是半解释型语言,很容易被反汇编后拿到源代码文件,我们可以在重要的交互功能使用C语言代替。2、效率,C语言比起java来说效率要高出很多。JNI和NDK的区别?从工具上说,NDK其实多了一个把.so和.apk打包的工具,而JNI开发并没有打包,只是把.so文件放到文件系统的特定位置。从编译库说,NDK开发C/C++只能能使用NDK自带的有限的头文件,而使用JNI则可以使用文件系统中带的头文件。从编写方式说,它们一样。详解1、JNI元素1、JNI组织结构JNI函数表的组成就像C++的虚函数表,虚拟机可以运行多张函数表。JNI接口指针仅在当前线程中起作用,指针不能从一个线程进入另一个线程,但可以在不同的线程中调用本地方法。2、原始数据Jobject对象引用类型Java类型本地类型(JNI)描述boolean(布尔型)jboolean无符号8个比特byte(字节型)jbyte有符号8个比特char(字符型)jchar无符号16个比特short(短整型)jshort有符号16个比特int(整型)jint有符号32个比特long(长整型)jlong有符号64个比特float(浮点型)jfloat32个比特double(双精度浮点型)jdouble64个比特void(空型)voidN/A函数操作函数Java数组类型本地类型说明GetBooleanArrayElementsjbooleanArrayjbooleanReleaseBooleanArrayElements释放GetByteArrayElementsjbyteArrayjbyteReleaseByteArrayElements释放GetCharArrayElementsjcharArrayjcharReleaseShortArrayElements释放GetShortArrayElementsjshortArrayjshortReleaseBooleanArrayElements释放GetIntArrayElementsjintArrayjintReleaseIntArrayElements释放GetLongArrayElementsjlongArrayjlongReleaseLongArrayElements释放GetFloatArrayElementsjfloatArrayjfloatReleaseFloatArrayElements释放GetDoubleArrayElementsjdoubleArrayjdoubleReleaseDoubleArrayElements释放GetObjectArrayElement自定义对象objectSetObjectArrayElement自定义对象objectGetArrayLength获取数组大小NewTypeArray创建一个指定长度的原始数据类型的数组GetPrimitiveArrayCritical得到指向原始数据类型内容的指针,该方法可能使垃圾回收不能执行,该方法可能返回数组的拷贝,因此必须释放此资源。ReleasePrimitiveArrayCritical释放指向原始数据类型内容的指针,该方法可能使垃圾回收不能执行,该方法可能返回数组的拷贝,因此必须释放此资源。NewStringUTFjstring类型的方法转换GetStringUTFCharsjstring类型的方法转换DefineClass从原始类数据的缓冲区中加载类FindClass该函数用于加载本地定义的类。它将搜索由CLASSPATH环境变量为具有指定名称的类所指定的目录和zip文件GetObjectClass通过对象获取这个类。该函数比较简单,唯一注意的是对象不能为NULL,否则获取的class肯定返回也为NULLGetSuperclass获取父类或者说超类。如果clazz代表类class而非类object,则该函数返回由clazz所指定的类的超类。如果clazz指定类object或代表某个接口,则该函数返回NULLIsAssignableFrom确定clazz1的对象是否可安全地强制转换为clazz2Throw抛出java.lang.Throwable对象ThrowNew利用指定类的消息(由message指定)构造异常对象并抛出该异常ExceptionOccurred确定是否某个异常正被抛出。在平台相关代码调用ExceptionClear()或Java代码处理该异常前,异常将始终保持抛出状态ExceptionDescribe将异常及堆栈的回溯输出到系统错误报告信道(例如stderr)。该例程可便利调试操作ExceptionClear清除当前抛出的任何异常。如果当前无异常,则此例程不产生任何效果FatalError抛出致命错误并且不希望虚拟机进行修复。该函数无返回值NewGlobalRef创建obj参数所引用对象的新全局引用。obj参数既可以是全局引用,也可以是局部引用。全局引用通过调用DeleteGlobalRef()来显式撤消。DeleteGlobalRef删除globalRef所指向的全局引用DeleteLocalRef删除localRef所指向的局部引用AllocObject分配新Java对象而不调用该对象的任何构造函数。返回该对象的引用。clazz参数务必不要引用数组类。getObjectClass返回对象的类IsSameObject测试两个引用是否引用同一Java对象NewString利用Unicode字符数组构造新的java.lang.String对象GetStringLength返回Java字符串的长度(Unicode字符数)GetStringChars返回指向字符串的Unicode字符数组的指针。该指针在调用ReleaseStringchars()前一直有效ReleaseStringChars通知虚拟机平台相关代码无需再访问chars。参数chars是一个指针,可通过GetStringChars()从string获得NewStringUTF利用UTF-8字符数组构造新java.lang.String对象GetStringUTFLength以字节为单位返回字符串的UTF-8长度GetStringUTFChars返回指向字符串的UTF-8字符数组的指针。该数组在被ReleaseStringUTFChars()释放前将一直有效ReleaseStringUTFChars通知虚拟机平台相关代码无需再访问utf。utf参数是一个指针,可利用GetStringUTFChars()获得NewObjectArray构造新的数组,它将保存类elementClass中的对象。所有元素初始值均设为initialElementSetPrimitiveTypeArrayRegion将基本类型数组的某一区域从缓冲区中复制回来的一组函数GetFieldID返回类的实例(非静态)域的属性ID。该域由其名称及签名指定。访问器函数的GettypeField及SettypeField系列使用域ID检索对象域。GetFieldID()不能用于获取数组的长度域。应使用GetArrayLength()。GettypeField该访问器例程系列返回对象的实例(非静态)域的值。要访问的域由通过调用GetFieldID()而得到的域ID指定。SettypeField该访问器例程系列设置对象的实例(非静态)属性的值。要访问的属性由通过调用SetFieldID()而得到的属性ID指定。GetStaticFieldIDGetStatictypeField同上,只不过是静态属性。SetStatictypeFieldGetMethodID返回类或接口实例(非静态)方法的方法ID。方法可在某个clazz的超类中定义,也可从clazz继承。该方法由其名称和签名决定。GetMethodID()可使未初始化的类初始化。要获得构造函数的方法ID,应将init作为方法名,同时将void(V)作为返回类型。CallVoidMethodCallObjectMethodCallBooleanMethodCallByteMethodCallCharMethodCallShortMethodCallIntMethodCallLongMethodCallFloatMethodCallDoubleMethodGetStaticMethodID调用静态方法CalltypeMethodRegisterNatives向clazz参数指定的类注册本地方法。methods参数将指定JNINativeMethod结构的数组,其中包含本地方法的名称、签名和函数指针。nMethods参数将指定数组中的本地方法数。UnregisterNatives取消注册类的本地方法。类将返回到链接或注册了本地方法函数前的状态。该函数不应在常规平台相关代码中使用。相反,它可以为某些程序提供一种重新加载和重新链接本地库的途径。域描述符域Java语言ZbooleanBbyteCcharSshortIintJlongFfloatDdouble引用类型则为L+该类型类描述符+。数组,其为:[+其类型的域描述符+。多维数组则是n个[+该类型的域描述符,N代表的是几维数组。[html]viewplaincopy1.String类型的域描述符为Ljava/lang/String;2.3.[+其类型的域描述符+;4.int[]其描述符为[I5.float[]其描述符为[F6.String[]其描述符为[Ljava/lang/String;7.Object[]类型的域描述符为[Ljava/lang/Object;8.int[][]其描述符为[[I9.float[][]其描述符为[[F将参数类型的域描述符按照申明顺序放入一对括号中后跟返回值类型的域描述符,规则如下:(参数的域描述符的叠加)返回类型描述符。对于,没有返回值的,用V(表示void型)表示。举例如下:[html]viewplaincopy1.Java层方法JNI函数签名2.Stringtest()Ljava/lang/String;3.intf(inti,Objectobject)(ILjava/lang/Object;)I4.voidset(byte[]bytes)([B)VJNIEnv与JavaVMJNIEnv概念:是一个线程相关的结构体,该结构体代表了Java在本线程的运行环境;JNIEnv与JavaVM:注意区分这两个概念;--JavaVM:JavaVM是Java虚拟机在JNI层的代表,JNI全局只有一个;--JNIEnv:JavaVM在线程中的代表,每个线程都有一个,JNI中可能有很多个JNIEnv;JNIEnv作用:--调用Java函数:JNIEnv代表Java运行环境,可以使用JNIEnv调用Java中的代码;--操作Java对象:Java对象传入JNI层就是Jobject对象,需要使用JNIEnv来操作这个Java对象;JNIEnv体系结构线程相关:JNIEnv是线程相关的,即在每个线程中都有一个JNIEnv指针,每个JNIEnv都是线程专有的,其它线程不能使用本线程中的JNIEnv,线程A不能调用线程B的JNIEnv;JNIEnv不能跨线程:--当前线程有效:JNIEnv只在当前线程有效,JNIE