深入理解JNI---碎碎念2

来源:互联网 发布:奉化房产信息网域名 编辑:程序博客网 时间:2024/05/21 11:12

JNI

Java Native Interface是一种技术,通过这种技术可以实现:

1)        java程序中的函数可以调用native语言中的函数;

2)        native程序中的函数可以调用java层的函数;

 

JNI技术根本是如何将java层的函数对应到native层,如何在native层调用java传递的参数。Java层调用native层需要在native层是对该函数进行注册,注册又分为静态注册和动态注册,注册之后在java层中声明的native方法就可以在native层实现。Native层的方法传入的java层的参数,又需要调用参数的方法。

 

Java层调用:

public class MediaScanner{

      static{

         /*加载对应的JNI库,media_jniJNI库的名字。在实际加载中会拓展成libmedia_jni.so,windows下拓展成media_jni.dll*/

         System.loadLibrary("media_jni");// 加载so文件

         native_init();//直接调用native

      }

      private static native final void native_init();

   }

 

如何将native层的方法对应到privatestaticnativefinalvoidnative_init()就是注册的过程;

静态方法注册:

1 先编写java代码,生成.class文件;

2 使用java工具程序javah,javah –o output packagename.classname, 这样就会生成一个output.h的jni层头文件,文件里包括生成对应的jni的函数声明,实现其函数就可以了。(方法名包括java层的报名,将.改为_)

 

当java层调用native_init函数时,它会从对应的JNI库中寻找Java_android_media_MediaScanner_native_init函数,如果没有就会报错。如果找到,则会为这个native_init和Java_android_media_MediaScanner_native_init建立关联关系,其实就保存JNI层函数的函数指针。

 

静态注册的弊端

1 需要编译所有声明了native函数的java类,每个所生成的class都用javah生成一个头文件;

2 javah生成的JNI层函数名特别长,书写不变;

3 初次调用native函数时要根据函数搜索对应的JNI层函数来建立关联关系,影响效率;

 

动态注册:

在jni中有一个JNINativeMethid结构来保存javaNative和jni函数的一一对应关系,其结构体

typedef struct{

// java中Native函数的名字,不用携带包的路径,如”native_init”

const char* name;

// java函数的签名信息,用字符串表示,是参数类型和返回值类型的组合

const char * signature;

void * fnPtr; // JNI层的函数指针,void *类型;

}

 

AndroidRunTime类提供了一个registerNativeMethods函数完成,registerNativeMethods的实现如下:

IntAndroidRuntime::registerNativeMethods(JNIEnv * env, const char * className,const JNINativeMethod * gMethods, int numMethods)

{

       returnjniRegisterNativeMethods(env,className,gMethods,numMethosd);

}

 

int iniRegisterNativeMethods(JNIEnv * env,const char * className, const JNINativeMethod * gMethods, int numMethods)

{

       jclassclazz;

clazz = (*env)->FindClass(env,className);

……

// 调用env的RegisterNatives函数

if((*env)->RegisterNatives(env,clazz,gMethods,numMethods)<0){

       return-1;

}

return 0;

}

 

当Java层通过System.loadLibary加载完成JNI动态库后,紧接着会查找该库中的一个叫JNI_OnLoad的函数。如果有就调用,动态注册的工作就在这里完成。

 

数据类型转换:

java层到Native的数据类型对应

1 基本数据类型转换:

 

2 引用数据类型的转换

 

JNIEnv

JNI_OnLoad的参数JavaVM * vm,void*reserved;调用JavaVM的AttachCurrentThread函数就可以获取这个线程的JNIEnv结构体;在线程退出前需要调用JavaVM的DetachCurrentThread函数来释放对应资源。

 

通过JNIEnv操作jobject

1 jfieldId和jobject

使用GetFieldId()和GetMethodId()函数获取jfieldID和jmethodID;

使用Call<type>Method()执行函数,静态方法使用CallStatic<type>Method执行函数;type值返回类型。

 

使用Get<type>Filed() 和Get<type>Field()方法获取和设置jobject的属性值。

 

参数类型签名的对应

 

异常处理和垃圾回收……略

0 0
原创粉丝点击