Android中JNI 的一些常用说明 JNI_OnLoad registerNatives registerNativeMethods


转自:http://blog.csdn.net/jianguo_liao19840726/article/details/6719224

Android JNI和NDK关系
1、什么JNI
Java Native Interface (JNI)标准是java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI 是本地编程接口,它使得在 Java 虚拟机 (VM) 内部运行的 Java 代码能够与用其它编程语言(如 C、C++ 和汇编语言)编写的应用程序和库进行交互操作。
上面过程分为2个部分:
第一、用C语言生成一个库文件。
第二、在java中调用这个库文件的函数。
2、NDK
NDK全称:Native Development Kit。
NDK是一系列工具的集合。
* NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成apk。这些工具对开发者的帮助是巨大的。
* NDK集成了交叉编译器,并提供了相应的mk文件隔离CPU、平台、ABI等差异,开发人员只需要简单修改mk文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so。
* NDK可以自动地将so和Java应用一起打包,极大地减轻了开发人员的打包工作。
个人理解,NDK就是能够方便快捷开发.so文件的工具。
JNI的过程比较复杂,生成.so需要大量操作,而NDK就是简化了这个过程。


registerNativeMethods


传统java Jni方式:1.编写带有native方法的Java类;--->2.使用javah命令生成.h头文件;--->3.编写代码实现头文件中的方法,这样的“官方” 流程,但也许有人无法忍受那“丑陋”的方法名称,

通用方式:RegisterNatives方法能帮助你把c/c++中的方法隐射到Java中的native方法,而无需遵循特定的方法命名格式。应用层级的Java类别透过VM而呼叫到本地函数。一般是仰赖VM去寻找*.so里的本地函数。如果需要连续呼叫很多次,每次都需要寻找一遍,会多花许多时间。此时,组件开发者可以自行将本地函数向VM进行登记,VM调registerNativeMethods()函数的用途有二:  (1)更有效率去找到函数。  (2)可在执行期间进行抽换。由于gMethods[]是一个<名称,函数指针>对照表,在程序执行时,可多次呼叫registerNativeMethods()函数来更换本地函数之指针,而达到弹性抽换本地函数之目的。

[cpp] view plain copy
  1. cpp文件中
  2. staticJNINativeMethodmethods[]={
  3. {"native_setText","([BJI)I",(void*)native_setText},
  4. {"native_clearText","(I)I",(void*)native_clearText},
  5. {"native_create","(I)I",(void*)native_create},
  6. {"native_start","()I",(void*)native_start},
  7. {"native_next","()I",(void*)native_next},
  8. {"native_flush","()I",(void*)native_flush},
  9. {"native_stop","()I",(void*)native_stop},
  10. {"native_pause","()I",(void*)native_pause},
  11. {"native_resume","()I",(void*)native_resume},
  12. {"native_get_current_position","()J",(void*)native_get_current_position},
  13. {"native_setSpeed","(I)I",(void*)native_setSpeed},
  14. {"native_getSynSpeed","()I",(void*)native_getSynSpeed},
  15. {"native_finalize","()I",(void*)native_finalize},
  16. {"native_delete","()I",(void*)native_delete},
  17. };
  18. //ClasspathnameforRegister
  19. staticconstchar*classPathName="android/tts/TTS";
  20. /*
  21. *Registerseveralnativemethodsforoneclass.
  22. */
  23. staticintregisterNativeMethods(JNIEnv*env,constchar*className,
  24. JNINativeMethod*gMethods,intnumMethods)
  25. /*
  26. *Registernativemethodsforallclassesweknowabout.
  27. *
  28. *returnsJNI_TRUEonsuccess.
  29. */
  30. staticintregisterNatives(JNIEnv*env)
  31. {
  32. if(!registerNativeMethods(env,classPathName,
  33. methods,sizeof(methods)/sizeof(methods[0]))){
  34. returnJNI_FALSE;
  35. }
  36. returnJNI_TRUE;
  37. }
  38. java文件中
  39. staticnativeintnative_create(intstreamType);
  40. staticnativeintnative_setSpeed(intspeed);
  41. staticnativeintnative_setText(bytestr[],longlength,intislast);
  42. staticnativeintnative_clearText(intappID);
  43. staticnativeintnative_start();
  44. staticnativeintnative_next();
  45. staticnativeintnative_flush();
  46. staticnativeintnative_pause();
  47. staticnativeintnative_resume();
  48. staticnativeintnative_stop();
  49. staticnativeintnative_finalize();
  50. staticnativeintnative_delete();
  51. staticnativeintnative_getSynSpeed();
  52. staticnativebooleannative_isPlaying();
  53. staticnativelongnative_get_current_position();


JNI组件的入口函数——JNI_OnLoad()、JNI_OnUnload()

JNI组件被成功加载和卸载时,会进行函数回调,当VM执行到System.loadLibrary(xxx)函数时,首先会去执行JNI组件中的JNI_OnLoad()函数,而当VM释放该组件时会呼叫JNI_OnUnload()函数。先看示例代码:


[java] view plain copy
  1. typedefunion{
  2. JNIEnv*env;
  3. void*venv;
  4. }UnionJNIEnvToVoid;
  5. /*Thisfunctionwillbecallwhenthelibraryfirstbeloaded*/
  6. jintJNI_OnLoad(JavaVM*vm,void*reserved)
  7. {
  8. UnionJNIEnvToVoiduenv;
  9. JNIEnv*env=NULL;
  10. LOGI("JNI_OnLoad!");
  11. if(vm->GetEnv((void**)&uenv.venv,JNI_VERSION_1_4)!=JNI_OK){
  12. LOGE("ERROR:GetEnvfailed");
  13. return-1;
  14. }
  15. env=uenv.env;;
  16. if(registerNatives(env)!=JNI_TRUE){
  17. LOGE("ERROR:registerNativesfailed");
  18. return-1;
  19. }
  20. returnJNI_VERSION_1_4;
  21. }

JNI_OnLoad()有两个重要的作用:

  • 指定JNI版本:告诉VM该组件使用那一个JNI版本(若未提供JNI_OnLoad()函数,VM会默认该使用最老的JNI 1.1版),如果要使用新版本的JNI,例如JNI 1.4版,则必须由JNI_OnLoad()函数返回常量JNI_VERSION_1_4(该常量定义在jni.h中) 来告知VM。
  • 初始化设定,当VM执行到System.loadLibrary()函数时,会立即先呼叫JNI_OnLoad()方法,因此在该方法中进行各种资源的初始化操作最为恰当。

JNI_OnUnload()的作用与JNI_OnLoad()对应,当VM释放JNI组件时会呼叫它,因此在该方法中进行善后清理,资源释放的动作最为合适。


JNI中的日志输出
你一定非常熟悉在Java代码中使用Log.x(TAG,“message”)系列方法,在c/c++代码中也一样,不过首先你要include相关头文件。遗憾的是你使用不同的编译环境( 请参考上文中两种编译环境的介绍) ,对应的头文件略有不同。。
如果是在完整源码编译环境下,只要include <utils/Log.h>头文件,就可以使用对应的LOGI、LOGD等方法了,同时请定义LOG_TAG,LOG_NDEBUG等宏值,示例代码如下:

[cpp] view plain copy
  1. #defineLOG_TAG"HelloJni"
  2. #defineLOG_NDEBUG0
  3. #defineLOG_NIDEBUG0
  4. #defineLOG_NDDEBUG0
  5. #include<string.h>
  6. #include<jni.h>
  7. #include<utils/Log.h>
  8. jstringJava_com_inc_android_ime_HelloJni_stringFromJNI(JNIEnv*env,jobjectthiz){
  9. LOGI("CallstringFromJNI!\n");
  10. return(*env)->NewStringUTF(env,"HellofromJNI(中文)!");
  11. }

JNI 的对应数据类型针对java和c++

c/c++方法和Java方法之间映射关系的关键是 JNINativeMethod 结构,该结构定义在jni.h中,具体定义如下:

[cpp] view plain copy
  1. typedefstruct{
  2. constchar*name;//java方法名称
  3. constchar*signature;//java方法签名
  4. void*fnPtr;//c/c++的函数指针
  5. }JNINativeMethod;

参照上文示例中初始化该结构的代码:

[cpp] view plain copy
  1. //定义方法隐射关系
  2. staticJNINativeMethodmethods[]={
  3. {"sayHello","(Ljava/lang/String;)Ljava/lang/String;",(void*)sayHello},
  4. };

其中比较难以理解的是第二个参数——signature字段的取值,实际上这些字符与函数的参数类型/返回类型一一对应,其中"()" 中的字符表示参数,后面的则代表返回值。例如"()V" 就表示void func(),"(II)V" 表示 void func(int, int),具体的每一个字符的对应关系如下:

字符 Java类型 C/C++类型
V void void
Z jboolean boolean
I jint int
J jlong long
D jdouble double
F jfloat float
B jbyte byte
C jchar char
S jshort short

数组则以"["开始,用两个字符表示:

字符 java类型 c/c++类型
[Z jbooleanArray boolean[]
[I jintArray int[]
[F jfloatArray float[]
[B jbyteArray byte[]
[C jcharArray char[]
[S jshortArray short[]
[D jdoubleArray double[]
[J jlongArray long[]

上面的都是基本类型,如果参数是Java类,则以"L"开头,以";"结尾,中间是用"/"隔开包及类名,而其对应的C函数的参数则为jobject,一个例外是String类,它对应C类型jstring,例如:Ljava/lang /String; 、Ljava/net/Socket; 等,如果JAVA函数位于一个嵌入类(也被称为内部类),则用$作为类名间的分隔符,例如:"Landroid/os/FileUtils$FileStatus;"。


In C, all other JNI reference types are defined to be the same as jobject. For example:

typedef jobject jclass; 

In C++, JNI introduces a set of dummy classes to enforce the subtyping relationship. For example:

class _jobject {}; class _jclass : public _jobject {}; ... typedef _jobject *jobject; typedef _jclass *jclass; 

Field and Method IDs

Method and field IDs are regular C pointer types:

struct _jfieldID;              /* opaque structure */ typedef struct _jfieldID *jfieldID;   /* field IDs */  struct _jmethodID;              /* opaque structure */ typedef struct _jmethodID *jmethodID; /* method IDs */ 

The Value Type

Thejvalueunion type is used as the element type in argument arrays. It is declared as follows:

typedef union jvalue {     jboolean z;     jbyte    b;     jchar    c;     jshort   s;     jint     i;     jlong    j;     jfloat   f;     jdouble  d;     jobject  l; } jvalue; 

Type Signatures

The JNI uses the Java VM’s representation of type signatures.Table3-2shows these type signatures.

Table3-2 Java VM Type Signatures
Type Signature Java Type
Z boolean
B byte
C char
S short
I int
J long
F float
D double
L fully-qualified-class ; fully-qualified-class
[ type type[]
( arg-types ) ret-type method type

For example, the Java method:

long f (int n, String s, int[] arr); 

has the following type signature:

(ILjava/lang/String;[I)J 



参考的资料:http://download.oracle.com/javase/1.5.0/docs/guide/jni/spec/types.html#wp568

http://www.top-e.org/jiaoshi/html/?168.html

http://neillife.blogspot.com/2009/01/how-to-add-new-module-to-android.html

http://blog.csdn.net/zhenyongyuan123/article/details/5862054

http://download.oracle.com/javase/1.5.0/docs/guide/jni/spec/jniTOC.html

http://cnetwei.iteye.com/blog/825306

更多相关文章

  1. Android中工作线程与主线程同步方式
  2. android中Bitmap的放大和缩小的方法
  3. Android事件分发和View绘制流程分析(三)
  4. Android(安卓)最新获取手机内置存储大小,SD卡存储空间大小方法
  5. Android遍历文件Listfile返回值为null问题解决方法适用Android8.
  6. 浅谈Java中Collections.sort对List排序的两种方法
  7. 箭头函数的基础使用
  8. Python技巧匿名函数、回调函数和高阶函数
  9. Python list sort方法的具体使用

随机推荐

  1. android中延迟执行某个任务
  2. 记录一下八款开源 Android(安卓)游戏引擎
  3. Android(安卓)之 Project Butter 详细介
  4. Android多媒体学习一:Android中Image的简
  5. Android开发环境的搭建
  6. android手机通过串口蓝牙透传模块与AVR单
  7. Android防止内存溢出浅析
  8. android init进程说明
  9. android 桌面程序 滑动抽屉 SlidingDraw,
  10. Android作业:一个3D相册源码