天天看点

Android NDK开发之JNI基础知识

JAVA层与JNI层数据类型的对应

下面是一个测试方法

public native void test(char c,short s,byte by,int i,long l,float f,double d,boolean b,String str,Object o,Test t,int[] arr);
           

jni层面生成的函数原型

JNIEXPORT void JNICALL
Java_com_kltz88_car_jnidemo_Test_test(JNIEnv *env, jobject instance, jbyte by, jchar c, jshort s, jint i,
                                      jlong l, jfloat f, jdouble d, jboolean b, jstring str_,
                                      jobject o, jobject t, jintArray arr);
           

我们会发现基本数据类型直接会有一种对应关系

[img]http://dl2.iteye.com/upload/attachment/0113/2209/05cbff65-0768-3aa3-8312-b476940ec2fa.png[/img]

其实只是使用了typedef重新定义了一下

进一步还会发现,引用类型也存在一定的对应关系

[img]http://dl2.iteye.com/upload/attachment/0113/2211/9b978427-d470-3d9c-b913-e773db941c94.png[/img]

也是通过typedef重新定义了一下,都是一个指针

方法签名

字段描述

[img]http://dl2.iteye.com/upload/attachment/0113/2213/1b52b80a-5576-3084-800f-f716a571fa6e.png[/img]

值得注意的是

- 类是使用L全限定名;,比如String, 其签名为Ljava/lang/util/String;

- 数组是使用[类型签名, 比如 [B

方法描述

[img]http://dl2.iteye.com/upload/attachment/0113/2215/1bce8fc7-2a5d-39be-9cd8-8487e594f619.png[/img]

JNI层暴露的方法

JNI层访问和修改JAVA实例变量与静态变量

由于JNI函数是直接操作JVM中的数据结构,不受Java访问修饰符的限制。即,在本地代码中可以调用JNI函数可以访问Java对象中的非public属性和方法

访问和修改实例变量操作步聚

[list=1]

[*]调用GetObjectClass函数获取实例对象的Class引用

[*]调用GetFieldID函数获取Class引用中某个实例变量的ID

[*]调用GetXXXField(如GetObjectField)函数获取变量的值,需要传入实例变量所属对象和变量ID

[*]调用SetXXXField(如SetObjectField)函数修改变量的值,需要传入实例变量所属对象、变量ID和变量的值

[/list]

访问和修改静态变量操作步聚

[list=1]

[*]调用FindClass函数获取类的Class引用

[*]调用GetStaticFieldID函数获取Class引用中某个静态变量ID

[*]调用GetStaticXXXField(如GetStaticIntField)函数获取静态变量的值,需要传入变量所属Class的引用和变量ID

[*]调用SetStaticXXXField(SetStaticIntField)函数设置静态变量的值,需要传入变量所属Class的引用、变量ID和变量的值

[/list]

JNI层访问和修改JAVA实例方法与静态方法

调用静态方法使用CallStaticXXXMethod/V/A函数,XXX代表返回值的数据类型。如:CallStaticIntMethod

调用实例方法使用CallXXXMethod/V/A函数,XXX代表返回的数据类型,如:CallIntMethod

获取一个实例方法的ID,使用GetMethodID函数,传入方法名称和方法签名

jmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
           

获以一个静态方法的ID,使用GetStaticMethodID函数,传入方法名称和方法签名

jmethodID   (*GetStaticMethodID)(JNIEnv*, jclass, const char*, const char*);
           

获取构造方法ID,方法名称使用”<init>”,比如获取默认构造方法

(*env)->GetMethodID(env,clazz, "<init>","()V");
           

获取一个类的Class实例,使用FindClass函数,传入类描述符。JVM会从classpath目录下开始搜索。

jclass      (*FindClass)(JNIEnv*, const char*);
           

创建一个类的实例,使用NewObject函数,传入Class引用和构造方法ID

删除局部变量引用,使用DeleteLocalRef,传入引用变量

方法签名格式:(形参参数列表)返回值类型。注意:形参参数列表之间不需要用空格或其它字符分隔

类描述符格式:L包名路径/类名;,包名之间用/分隔。如:Ljava/lang/String;

调用GetMethodID获取方法ID和调用FindClass获取Class实例后,要做异常判断,判断返回值是否为NULL