[android jni]android JNI 详细介绍
来源:互联网 发布:js数组去掉空格 编辑:程序博客网 时间:2024/05/17 20:27
主题:
●Java和JNI之间的数据对应关系
●数组操作
●相关数据处理函数,如字符串的创建,运算,转换
1. Java和JNI之间的数据对应关系
很多人都很疑惑为什么要定义数的数据类型呢,为什么不延用Java中的定义呢,
有这个疑惑的童鞋是平时没有注意数据类型大小的定义,Android这么做目的是因为Java中的基本数据类型的字节长度,并不是根据cpu的运算能力来定义的,如int在java中永远是4字节长,所以android这么做是为了兼容java的定义。
android jni 数据类型都定义在jni.h中的,我们贴出来方便大家平时的检阅:
- typedef uint8_t jboolean; /* unsigned 8 bits */
- typedef int8_t jbyte; /* signed 8 bits */
- typedef uint16_t jchar; /* unsigned 16 bits */
- typedef int16_t jshort; /* signed 16 bits */
- typedef int32_t jint; /* signed 32 bits */
- typedef int64_t jlong; /* signed 64 bits */
- typedef float jfloat; /* 32-bit IEEE 754 */
- typedef double jdouble; /* 64-bit IEEE 754 */
- typedef jint jsize;
- class _jobject {};
- class _jclass : public _jobject {};
- class _jstring : public _jobject {};
- class _jarray : public _jobject {};
- class _jobjectArray : public _jarray {};
- class _jbooleanArray : public _jarray {};
- class _jbyteArray : public _jarray {};
- class _jcharArray : public _jarray {};
- class _jshortArray : public _jarray {};
- class _jintArray : public _jarray {};
- class _jlongArray : public _jarray {};
- class _jfloatArray : public _jarray {};
- class _jdoubleArray : public _jarray {};
- class _jthrowable : public _jobject {};
- typedef _jobject* jobject;
- typedef _jclass* jclass;
- typedef _jstring* jstring;
- typedef _jarray* jarray;
- typedef _jobjectArray* jobjectArray;
- typedef _jbooleanArray* jbooleanArray;
- typedef _jbyteArray* jbyteArray;
- typedef _jcharArray* jcharArray;
- typedef _jshortArray* jshortArray;
- typedef _jintArray* jintArray;
- typedef _jlongArray* jlongArray;
- typedef _jfloatArray* jfloatArray;
- typedef _jdoubleArray* jdoubleArray;
- typedef _jthrowable* jthrowable;
- typedef _jobject* jweak;
- typedef union jvalue {
- jboolean z;
- jbyte b;
- jchar c;
- jshort s;
- jint i;
- jlong j;
- jfloat f;
- jdouble d;
- jobject l;
- } jvalue;
2. 数组操作
1)获取长度
jarray array;
env->GetArrayLength(array)
2)访问数组元素
这个要取决于数组是对象还是基本数据类型。
对象数组:
jobjectArray array = ... ;
int i, j;
jobject object = env->GetObjectArrayElement(array, i);
env->GetObjectArrayElement(array, j, x);
基本数据:
xxx* a = env->GetxxxArrayElements(array, null) //把xxx换成double, int, boolean等等
然后可以a[i]来访问
用完以后一定要用下面的方法去Release, 这样才会把修改写回实现的地址。
env->ReleasexxxArrayElements(array, a, 0);
大范围数组元素操作
void GetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len, jboolean* buf) //buf用来返回数组段的起始地址
void SetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len, const jboolean* buf)
3)创建Java数组
jobjectArray array = env->NewObjectArray(100, clazz, NULL); // 100表示长,clazz java类对象, NULL类对象
jdoubleArray array = env->NewDoubleArray(100); //创建基本数据类型数组
3. 字符串操作
jstring NewString(const jchar* unicodeChars, jsize len)
jsize GetStringLength(jstring string)
const jchar* GetStringChars(jstring string, jboolean* isCopy)
void ReleaseStringChars(jstring string, const jchar* chars)
jstring NewStringUTF(const char* bytes)
jsize GetStringUTFLength(jstring string)
const char* GetStringUTFChars(jstring string, jboolean* isCopy)
void ReleaseStringUTFChars(jstring string, const char* utf)
主题:
● 获取Java类
● 访问Java属性
●访问Java方法
●创建Java对象
●抛异常
1. 获取Java类
方法一:
jclass clazz = env->GetObjectClass(thisObj);
方法二:
jclass cls = env->FindClass("com/lht/JNITest");
以上方法是先获取到Class对象,当然这是c++的写法,c的写法是不一定的,我是喜欢用c++的方式来实现JNI
2. 读写Java属性
以后是用到的JNI 函数
- jfieldID (*GetFieldID)(JNIEnv*, jclass, const char*, const char*);
- jobject (*GetObjectField)(JNIEnv*, jobject, jfieldID);
- jboolean (*GetBooleanField)(JNIEnv*, jobject, jfieldID);
- jbyte (*GetByteField)(JNIEnv*, jobject, jfieldID);
- jchar (*GetCharField)(JNIEnv*, jobject, jfieldID);
- jshort (*GetShortField)(JNIEnv*, jobject, jfieldID);
- jint (*GetIntField)(JNIEnv*, jobject, jfieldID);
- jlong (*GetLongField)(JNIEnv*, jobject, jfieldID);
- jfloat (*GetFloatField)(JNIEnv*, jobject, jfieldID);
- jdouble (*GetDoubleField)(JNIEnv*, jobject, jfieldID);
- void (*SetObjectField)(JNIEnv*, jobject, jfieldID, jobject);
- void (*SetBooleanField)(JNIEnv*, jobject, jfieldID, jboolean);
- void (*SetByteField)(JNIEnv*, jobject, jfieldID, jbyte);
- void (*SetCharField)(JNIEnv*, jobject, jfieldID, jchar);
- void (*SetShortField)(JNIEnv*, jobject, jfieldID, jshort);
- void (*SetIntField)(JNIEnv*, jobject, jfieldID, jint);
- void (*SetLongField)(JNIEnv*, jobject, jfieldID, jlong);
- void (*SetFloatField)(JNIEnv*, jobject, jfieldID, jfloat);
- void (*SetDoubleField)(JNIEnv*, jobject, jfieldID, jdouble);
我们先看一下
jfieldID (*GetFieldID)(JNIEnv*, jclass, const char*, const char*);//这个方法相当的耗时,请不要频繁的使用,当读到以后应该保存起来
JNIEnv*就不用说了,jclass是要访问属性的类的class对象,如何获取已在上一节讲述了,第三个参数为属性名称,如你定义了一个String mName;那么参数为"mName",
第四个参数是属性的签名,mName的类型为String,那么它的签名应该是指"Ljava/lang/String;"
所以我们代码写成:jfieldID nameId = env->GetFieldID(class, "mName", "Ljava/lang/String;")
拿到nameId我们再来看看
jString name = (jString)env->GetObjectField(jObj, nameId);
jObj是java调用传入的this对象。
如果属性域是静态的,那么方法为GetStaticFieldID, GetStaticObjectField
获取完了以后,我们要设置呢?
env->SetObjectField(jObj, nameId, name); //第三个参数为值
3. 访问Java方法
根读写java属性的步骤一致。
先获取方法的ID
jmethodID GetMethodID(jclass clazz, const char* name, const char* sig)
jclass, 就是要访问的类的类对象,是需要根据本篇的第一节的描述获取的jclass对象
name, 方法名称
sig, 方法的签名,如:“(Ljava/lang/String;I)V”
CallVoidMethod(jclass clazz,, methodID, ...);
CallVoidMethod(jclass clazz,, methodID, jvalue args[]);
CallVoidMethod(jclass clazz,, methodID, va_list args);
... , 用来传递参数,这个相信在Java中用的比较的多,如println类,你可以在后面跟很多个参数,如jString,jint and so on.
jvalue是一个枚举类:
typedef union jvalue {
jboolean z;
jbyte b;
jchar c;
jshort s;
jint i;
jlong j;
jfloat f;
jdouble d;
jobject l;
} jvalue;
va_list,是c语言中用来解决变参的宏,
后面两个调用方法不用管,一般我们用第一个就够了。
调用静态的方法:
跟上面的没有什么区别,只是分别用GetStaticMethodID和CallStaticVoidMethod方法
CallStaticObjectMethod(class, methodid, env->newStringUTF("java.class.path"))
4. 在JNI中创建Java类对象
jobject NewObject(jclass clazz, jmethodID methodID, ...)
参数说明:
clazz, java类
jmethodID, 构造函数ID
..., 构造参数
5. 抛异常
有两个接口可以实现
jint (*Throw)(JNIEnv*, jthrowable);
jint (*ThrowNew)(JNIEnv *, jclass, const char *);
6. 创建Java虚拟机
在非JNI的代码中,我们可以通过创建一个Java虚拟机来访问Java类
JavaVMOption options[1];
JavaVMInitArgs vm_args;
JavaVM *jvm;
JNIEnv *env;
options[0].optionString = "-Djava.class.path=.";
memset(&vm_args, 0, sizeof(vm_args));
vm_args.version = JNI_VERSION_1_4;
vm_args.nOption = 1;
vm_args.options = options;
JNI_CreateJavaVM(&jvm, (void**) & env, &vm_args);
●编码签名
BbyteCcharDdoubleFfloatJlongLclassname;类的类型SshortVvoidZbooleanIint例如:
void Employee(java.lang.String, double, java.util.Date)
具有如下签名:
"(Ljava/lang/String;DLjava/util/Date;)V"
需要说明的是以上的分号并不是参数分隔符
数组则需要在前后加“[”
如:
float[] [F
float[][] [[F
当然我们也可以不用自己去写这个签名
javap -s -private Employee,可以自动生成签名
- android jni 详细介绍
- [android jni]android JNI 详细介绍
- Android JNI介绍
- Android JNI技术介绍
- Android JNI知识介绍
- Android JNI 介绍
- Android JNI介绍
- Android JNI技术介绍
- 【android&&jni&&NDk】详细介绍每一步,让你轻松掌握android JNI NDk
- android jni开发详细步骤
- Android调用JNI详细步骤
- 详细Android Studio Jni 调试
- [JNI] Android JNI总结
- Java JNI 详细介绍
- Android JNI
- Android JNI
- android JNI
- Android JNI
- 为什么使用字符数组保存密码比使用String保存密码更好?
- 解决网页背景图片不能自动适应的方法
- 转换构造函数的应用。。
- 收藏文章
- struct和typedef struct
- [android jni]android JNI 详细介绍
- VC++6.0去掉单文档中的菜单,工具栏,状态栏
- DLL的编写方法
- 一行命令获取文件版本信息
- windows安装好express环境新建项目运行不了的问题
- SQL Server 全文索引查询T-SQL学习笔记
- 【二叉排序树 (2)】
- Android ListView控件基本用法
- 最大堆/最小堆