写程序的小男孩

JNI是Java Native Interface的缩写,JNI是一种机制,有了它就可以在java程序中调用其他native代码,或者使native代码调用java层的代码。也 就是说,有了JNI我们可以使Android项目中,java层与native层各自发挥所长并相互配合。如下图所示,JNI在Android中所处的位 置。

JNI相对与native层来说是一个接口,java层的程序想访问native层,必须通过JNI,反过来也一样。下面我们来看几个问题。

1,如何告诉VM(虚拟机)java层需要调用native层的哪些libs?

我们知道java程序是运行在VM上的,而Native层的libs则不然。所以为了让java层能访问native层的libs,必须得告诉VM要使用哪些native层的libs。下面看一段代码

public class MediaPlayer{…static {System.loadLibrary(“media_jni”);native_init();}… native_init();…}

可以看到上面的代码中,在MediaPlayer类中有一段static块包围起来的代码, 其中System.loadLibrary(“media_jni”)就是告诉VM去加载libmedia_jni.so这个动态库,那么这个动态库什么 时候被加载呢?因为static语句块的原因,所以在MediaPlayer第一次实例化的时候就会被加载了。这段代码中,我们还看到了一个函数 native_init(),该函数被申明为native型,就是告诉VM该函数由native层来实现。

2,香港服务器,如何做到java层到native层的映射。

所谓Java 层到native层的映射就是说JVM在调用 void native_init() 这个函数时,该怎么去找相应的动态链接库里面的函数。因为void native_init () 函数并没有在java文件中定义。

  这里有2种办法,

  一种是我们在C 文件中按照一定的命名规则来定义函数。

  假设上面的MediaPlayer类在android.media包内。

  我们的native层的代码可如下定义

  #include <jni.h>      #ifndef _Included_MediaPlayer  #define _Included_MediaPlayer  #ifdef __cplusplus   {  #endif  /*  * Class:   MediaPlayer  * Method:  init media player  * Signature: ()V  */  JNIEXPORT void JNICALL Java_android_media_MediaPlayer_native_init  (JNIEnv *, jobject);    #ifdef __cplusplus  }  #endif  #endif

  其中jobject参数是JVM的MediaPlayer调用native_init时的对象,JNIEnv* 是一个全局环境结构。

  这个命名规则,香港虚拟主机,香港虚拟主机,想必很容易看懂,两个修饰符JNIEXPORT JNICALL,应该分别用来兼容so和dll的导出函数的,JNICALL是用来兼容stdcall 等这些不同的函数调用方式的。

函数名字以Java开头,后面跟着的是声明这个函数的类的全路径,包括包名,最后是函数名。

  可以发现,这个函数名实在是很丑陋,难以阅读。

  第二种方法,我们可以进行动态注册:

  我们来看看Android源码里的MediaPlayer的native是怎么写的。

  当VM执行到System.loadLibrary()的时候就会去执行native libs中的JNI_OnLoad(JavaVM* vm, void* reserved)函数,因为JNI_OnLoad函数是从java层进入native层第一个调用的方法,所以可以在JNI_OnLoad函数中完成一些native层组件的初始化工作,同时更加重要的是,通常在JNI_jint JNI_OnLoad(JavaVM* vm, void* reserved)函数中会注册java层的native方法。下面看一段代码:

  

jint JNI_OnLoad(JavaVM* vm, void* reserved){JNIEnv* env = NULL;jint result = -1;(vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {LOGE();goto bail;}assert(env != NULL);if (register_android_media_MediaPlayer(env) < 0) {LOGE();goto bail;}if (register_android_media_MediaRecorder(env) < 0) {LOGE();goto bail;}>_android_media_MediaScanner(env) < 0) {LOGE();goto bail;}</span>if (register_android_media_MediaMetadataRetriever(env) < 0) {LOGE();goto bail;}if (register_android_media_AmrInputStream(env) < 0) {LOGE();goto bail;}if (register_android_media_ResampleInputStream(env) < 0) {LOGE();goto bail;}if (register_android_media_MediaProfiles(env) < 0) {LOGE();goto bail;}result = JNI_VERSION_1_4;bail:return result;}

请打开窗口,让我的灵魂与你的灵魂相拥。

写程序的小男孩

相关文章:

你感兴趣的文章:

标签云: