此系列记录Android NDK基础开发知识,在Android NDK开发基础篇(一)中介绍了NDK、JNI以及关系,包括AS创建JNI的项目及第一个函数解析,
- Java类型和native类型的映射关系
- jobject
- jclass
- JNIEnv 的基本使用
用于参数解析:
Java_com_kpa_jnijavademo_MainActivity_stringFromJNI(
JNIEnv *env,
jobject obj/* this */) {
return env->NewStringUTF(hello.c_str());
}
Java类型 | 本地类型 | JNI定义的别名 |
---|---|---|
int | long | jint/jsize |
short | short | jshort |
long | _int64 | jlong |
float | float | jfloat |
double | double | jdouble |
byte | signed char | jbyte |
boolean | unsigned char | jboolean |
char | unsigned char | jchar |
Object | _jobject* | jobject |
本地类型指的是在C/C++中的使用,JNI定义的别名是C/C++在JNI中的使用,不需要多记,后续回经常出现
jobject 表示的是Java中的Object类型,在参数中有两个不同的意义需要知道
jclass 表示Java的中的Class类
在下面的JNIEnv 中会解释jclass 在C/C++中的集中获取方法
JNIEnv 类型在native 中实际代表了Java在native中的Java环境 ,通过JNIEnv*指针可以对Java端的代码进行操作,为什么JNI开发中首先要了解对Java的操作呢?
JNI作为Java和C/C++的连接桥梁,自然能在C/C++中操作Java的对象,最起码我们在C/C++中的一系列操作完成之后,将结果返回给Java就需要用到Java操作,以此问题还有很多。
既然是代表了Java环境,那首先有这几个概念需要了解一下:
这是最起码操作一个Java对象应该具备的要素
Newobject
/**
*jclass : Class 对象(后续解释怎么获取一个class对象)
*methodID: 方法ID
**/
jobject NewObject(jclass clazz, jmethodID methodID, ...)
{
va_list args;
va_start(args, methodID);
jobject result = functions->NewObjectV(this, clazz, methodID, args);
va_end(args);
return result;
}
jmethodID 在JNI中表示一个指向method的指针,创建对象时的method哪里来呢? 没错就是构造方法
为了后续更好的理解 先看一下jclass 的获取方法
// 通过类的全名获取class 对象
jclass FindClass(const char* name)
{ return functions->FindClass(this, name); }
eg:
// 获取Java中Date 对象的Class对象
jclass date_clazz = env->FindClass("java/util/Date");
// 通过native方法中的jobject对象获取Class 对象
jclass GetObjectClass(jobject obj)
{ return functions->GetObjectClass(this, obj); }
eg:
Java_com_kpa_jnijavademo_JNIDemo_sayHello(JNIEnv *env, jobject thiz) {
// 根据native sayHello方法中jobject 的class 对象
jclass jniDemo = env->GetObjectClass(thiz);
}
//根据jclass 可以获取他的父类的jclass 对象
jclass GetSuperclass(jclass clazz)
{ return functions->GetSuperclass(this, clazz); }
GetMethodID/GetStaticMethodID
/**
* clazz 所在class 对象
* name: 方法名称
* sig: 方法签名(变量和方法在JNI中都是有签名的)
**/
jmethodID GetMethodID(jclass clazz, const char* name, const char* sig)
{ return functions->GetMethodID(this, clazz, name, sig); }
jmethodID GetStaticMethodID(jclass clazz, const char* name, const char* sig)
{ return functions->GetStaticMethodID(this, clazz, name, sig); }
GetFieldID/GetStaticFieldID
jfieldID GetFieldID(jclass clazz, const char* name, const char* sig)
{ return functions->GetFieldID(this, clazz, name, sig); }
jfieldID GetStaticFieldID(jclass clazz, const char* name, const char* sig)
{ return functions->GetStaticFieldID(this, clazz, name, sig); }
通过javap命令查看类中的属性和方法的签名
javap -s -p XXX.class
eg:
public class com.kpa.jnijavademo.Demo {
public int a;
descriptor: I
public com.kpa.jnijavademo.Demo();
descriptor: ()V //构造方法签名
public int add(int, int);
descriptor: (II)I
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
}
I、()V、(II)I都是签名
eg:
void createObj1(JNIEnv *env) {// native 创建Java对象
// 获取Java中的Date的Class对象
jclass date_clazz = env->FindClass("java/util/Date");
// 获取构造方法的ID 构造方法名称始终是
jmethodID mid_date = env->GetMethodID(date_clazz, "" , "()V");
// 生成Date对象
jobject date_obj = env->NewObject(date_clazz, mid_date);
jmethodID get_time_id = env->GetMethodID(date_clazz, "getTime", "()J");
jlong time = env->CallLongMethod(date_obj, get_time_id);
printf("时间 ==== %I64d", time);
}
然后看一下上面4.1中NewObject创建一个对象
eg:
// 获取Java中的Date的Class对象
jclass date_clazz = env->FindClass("java/util/Date");
// 获取构造方法的ID 构造方法名称始终是
jmethodID mid_date = env->GetMethodID(date_clazz, "" , "()V");
到此为止,介绍了JNI中如果获取对象的Class 对象,创建对象,以及获取方法、属性等功能。
在Android NDK特别篇中多介绍几个使用案例