
JNI——Java Native Interface,它是Java平台的一个特性(并不是Android系统特有的)。其实主要是定义了一些JNI函数,让开发者可以通过调用这些函数实现Java代码调用C/C++的代码,C/C++的代码也可以调用Java的代码,这样就可以发挥各个语言的特点了。那么怎么使用JNI呢,一般情况下我们首先是将写好的C/C++代码编译成对应平台的动态库(windows一般是dll文件,linux一般是so文件等),这里我们是针对Android平台,所以只讨论so库。由于JNI编程支持C和C++编程,这里我们的栗子都是使用C++,对于C的版本可能会有些差异,但是主要的内容还是一致的,大家可以触类旁通。
这里还是直接从代码说起,这样更加形象和直观,也便于理解。今天使用的Java代码如下:
这里我们定义了两个声明为native的方法,并声明了一块静态区域,在该静态区域类加载名为libmain.so的库,这里我们说是libmain.so库,但是加载的时候却只写了“main”,其实大家只要知道这是约定的就可以了。
C++代码如下:
这里引用了两个头文件,jni.h和mylog.h,其中jni.h是定义了很多我们使用的JNI函数和结构体,mylog.h是我自己定义的打印Android log的函数(功能和Java的Log类相同)。
这里暂时不讨论怎么编译成so库以及so库的一些规范。这里假定将上面的C++程序编译成了一个叫libmain.so的文件。在Java层使用System.loadLibarary("main")方法将该so库加载起来,使得dynamicLog()、staticLog()和对应的Java_com_github_songnick_jni_AndroidJni_staticLog()、nativeDynamicLog()两个native方法链接起来,当然这部分工作都是由Java虚拟机完成的,那么具体是怎么完成的,接下来将根据上面的代码进行分析。

在上面的代码中看到了JNIEXPORT和JNICALL关键字,这两个关键字是两个宏定义,他主要的作用就是说明该函数为JNI函数,在Java虚拟机加载的时候会链接对应的native方法,在AndroidJni.java的类中声明了staticLog()为native方法,他对应的JNI函数就是Java_com_github_songnick_jni_AndroidJni_staticLog(),那么是怎么链接的呢,在Java虚拟机加载so库时,如果发现含有上面两个宏定义的函数时就会链接到对应Java层的native方法,那么怎么知道对应Java中的哪个类的哪个native方法呢,我们仔细观察JNI函数名的构成其实是:Java_PkgName_ClassName_NativeMethodName,以Java为前缀,并且用“_”下划线将包名、类名以及native方法名连接起来就是对应的JNI函数了。一般情况下我们可以自己手动的去按照这个规则写,但是如果native方法特别多,那么还是有一定的工作量,并且在写的过程中不小心就有可能写错,其实Java给我们提供了javah的工具帮助生成相应的头文件。在生成的头文件中就是按照上面说的规则生成了对应的JNI函数,我们在开发的时候直接copy过去就可以了。c 类 static 函数c 类 static 函数这里上面的代码为例,在AndroidStudio中编译后,进入项目的目录app/build/intermediates/classes/debug下,运行如下命令:
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-57645-1.html
中国人爱好和平
先去追求那个不平凡去把
别说你双降就八连降我也只能喝粥