Android学习之JNI

概述

JNI是Java Native Interface的缩写,中文为Java本地调用

JNI可以实现两种功能:

(1)java程序中的函数可以调用native的函数(一般是C/C++编写的函数)

(2)Native的函数可以调用java层的函数

下面以MediaScanner为例,大概说明JNI的原理

Android学习之JNI_第1张图片

上图看出,对于JNI层的命名方式:lib模块名_jni.so(Native层库名_jni.so)。JNI层必须实现为动态库的形式,这样Java虚拟机才能加载,JNI本身用native语言来实现。


加载JNI库

加载JNI库是在类的静态块中完成的,静态块是在类加载时运行的,可以简单理解为在new一个对象之前就已经执行了。加载这个库的原因是可以在Java层通过库可以调用到Native层。

Android学习之JNI_第2张图片


注册JNI函数

究竟native_init()函数会调用native层的什么函数呢?以下注册是JNI注册流程图

Android学习之JNI_第3张图片

所以,要实现native层和Java层的关联,就要实现JNI_OnLoad和register_android_media_MediaScanner函数,如下图

JNI_OnLoad函数在android_media_MediaPlayer.cpp中实现

Android学习之JNI_第4张图片

register_android_media_MediaScanner函数在android_media_MediaScanner.cpp中实现

Android学习之JNI_第5张图片

其中参数gMethods的结构如下

Android学习之JNI_第6张图片

JNINativeMethod结构就把java层的方法和native层的方法关联起来了,第一个参数代表java层的方法名,第三个参数代表native层的方法名,第二个参数是函数的签名信息,由参数类型和返回值类型组成。以ProcessFile举例说明:

private native void processFile(String path, String mimeType, MediaScannerClient client);

"(Ljava/lang/String;Ljava/lang/String;Landroid/media/MediaScannerClient;)V“

由此可见,签名信息包含了native层方法的参数信息和返回值信息,括号内是参数类型的标识,引用类型的格式是“L包名”,包名中的”.“换成”/“,最右边的是返回值类型的标识,V代表void

签名信息只用于找到函数,因为java有重载,不用于数据传递

Android学习之JNI_第7张图片


JNI数据类型转换

Android学习之JNI_第8张图片

上图可看出,java层的数据类型在native层一一对应着一种数据类型,数据类型的转换,分为基本数据类型和引用数据类型。

基本数据类型转换

Android学习之JNI_第9张图片

引用数据类型转换

Android学习之JNI_第10张图片


JNI数据使用

native层如何获取到java层获取的数据?

JNIEnv是一个与线程相关的代表JNI环境的结构体,JNIEnv提供了一些函数操作Java层传下来的数据,如:

const char *mimeTypeStr = env->GetStringUTFChars(mimeType, NULL);


native层如何获取Java层传下来的对象?

对象无非由成员函数和成员变量组成,操作Java层传下来的对象,本质就是操作这些成员函数和成员变量,JNI中分别用jfieldID和jmethodID来表示java对象的成员变量和函数

jfieldID和jmethodID可通过JNIEnv得到,如

jmethodID mScanFileMethodID;

mScanFileMethodID = env->GetMethodID(
                                    mediaScannerClientInterface,
                                    "scanFile",
                                    "(Ljava/lang/String;JJZZ)V");

mEnv->CallVoidMethod(mClient, mScanFileMethodID, pathStr, lastModified,
                fileSize, isDirectory, noMedia);

通过上述代码,就可以调用java层的scanFile函数了


最后,各位看官辛苦了

Android学习之JNI_第11张图片

你可能感兴趣的:(Android学习之JNI)