Android JNI编程规范
来源:互联网 发布:网络攻防平台 编辑:程序博客网 时间:2024/05/22 01:34
Demo
//增加学生信息: addStu(JNIEnv *env,jobject valObj){ //获取jclass对象 jclass cls=env->GetObjectClass(valObj); //GetFieldID方法用到取到jclas中的name字段。参数列表(jclass对象,字段名称,字段类型) 这点类似于java的反射 jstring name =(jstring)env->GetObjectField(valObj,env->GetFieldID(cls,"name","Ljava/lang/String;")); jint age=(jint)env->GetObjectField(valObj,env->GetFieldID(cls,"age","I")); jint sex =(jint)env->GetObjectField(valObj,env->GetFieldID(cls,"sex","I")); //创建一个结构类型的对象 jstringToString方法用于把jstring类型转换成char * student stu={jstringToString(env,name),(int)age,(int)sex}; //往向量的末尾增加一个对象 stus.push_back(stu); }
//修改学生信息 upStu(JNIEnv *env,jobject obj,jobject objValue){ jclass cls=env->GetObjectClass(objValue); jstring name=(jstring)env->GetObjectField(objValue,env->GetFieldID(cls,"name","Ljava/lang/String;")); jint sex =(jint)env->GetObjectField(objValue,env->GetFieldID(cls,"sex","I")); jint age=(jint)env->GetObjectField(objValue,env->GetFieldID(cls,"age","I")); char * searchName =jstringToString(env,name); for(int i=0;i<stus.size();i++){ student stu=stus.at(i); if(strcmp(stu.name,searchName)==0){ stus.at(i).sex=(int)sex; stus.at(i).age=(int)age; } } }
//查询学生 getStu(JNIEnv *env,jobject obj,jstring str){ const char *nameStr=env->GetStringUTFChars(str,0); jclass objectClass =(env)->FindClass("com/myjni/activity/Student"); jfieldID name =env->GetFieldID(objectClass,"name","Ljava/lang/String;"); jfieldID sex =env->GetFieldID(objectClass,"sex","I"); jfieldID age =env->GetFieldID(objectClass,"age","I"); for(int i=0;i<stus.size();i++){ student stu=stus.at(i); if(strcmp(stu.name,nameStr)==0){ env->SetObjectField(obj,env->NewStringUTF(stus.at(i).name)); env->SetIntField(obj,sex,stus.at(i).sex); env->SetIntField(obj,age,stus.at(i).age); } } return obj; }
//获取所有学生信息 getStus(JNIEnv *env,jobject obj){ class objClass =(env)->FindClass("java/lang/Object"); jobjectArray args = 0; jsize len=stus.size(); args=env->NewObjectArray(len,objClass,0); jclass objectClass =(env)->FindClass("com/myjni/activity/Student"); jfieldID name=(env)->GetFieldID(objectClass,"name","Ljava/lang/String;"); jfieldID age=(env)->GetFieldID(objClass,"age","I"); jfieldID sex =(env)->GetFieldID(objClass,"sex","I"); for(int i=0;i<len;i++){ jobject tempObj =env->AllocObject(env->GetObjectClass(obj)); student stu=stus.at(i); env->SetObjectField(tempObj,name,env->NewStringUTF(stus.at(i).name)); env->SetObjectField(tempObj,age,stu.age); env->SetObjectField(tempObj,sex,stu.sex); env->SetObjectArrayElement(args,i,tempObj); } return args; //返回的是数组对象 }
类型签名:
Z boolean B byteC charS shortI intJ long F floatD doubleLjava/lang/String; String[I int[]
数据类型
基本数据类型: boolean byte char short int long float double --Java jboolean jbyte jchar jshort jint jlong jfloat jdouble --jni 引用数据类型: String Array[] Object --Java String : jstring是JNI对应于String的类型,但是和基本类型不同的是,jstring不能直接当做C++的string用。否则编译器会扔给你一个错误信息。 const char *str; str =env->GetStringUTFChars(prompt,false); //先将java中的String转换成chars if(str==null){ return null; } cout<<str<<endl; //可以进行字符数组的输出 env->ReleaseStringUTFChars(prompt,str); //注意释放存储,避免内存泄露 //如果要转换成string对象 char *tmpstr="returnStringSucceeded"; jstring str =env->NewStringUTF(tmpstr); //将char转换成jstring类型 总结: 将java中的String类型转换成JNI中de jstring类型 const char *chars=env->GetStringUTFChars(prompt,false); jstring str =env->NewStringUTF(chars); 数组类型: JNI为Java基本类型的数组提供了j*Array类型,比如int[] 对应的就是jintArray JNIEXPORT jint JNICALL Java_IntArray_sumArray(JNIEnv *env,jobject obj,jintArray arr){ jint *carr; carr =env->GetIntArrayElements(arr,false); if(carr==NULL){ return 0; } jintsum =0; for(int i=0;i<10;i++){ sum+=carr; } env->ReleaseIntArrayElements(arr,carr,0); return sum; } 总结: GetIntArrayElements和ReleaseIntArrayElements函数就死JNI提供用于处理int数组的函数。 二维数组和String数组: 在JNI中,二维数组和String数组都被视为object数组,因为数组和String被视为object。 JNIEXPORT jobjectArray JNICALL Java_ObjectArrayTest_initInt2DArray(JNIEnv *env,jclass cls,int size){ //因为要返回值,所以需要新建一个jobjectArray对象 jobjectArray result; //创建一个jclass的引用 jclass intArrCls = env->FindClass("[I"); //为result分配空间 result =env->NewObjectArray(size,intArrCls,NULL); for(int i=0;i<size;i++){ jint tmp[256]; //保证存储空间足够大 //为一维int数组iarr分配空间 jintArray iarr=env->NewIntArray(size); for(int j=0;j<size;j++){ tmp[j]=i+j; } //为iarr赋值 env->SetIntArrayRegion(iarr,0,size,tmp); //为result的第i个元素赋值 env->StObjectArrayElements(result,i,iarr); env->DeleteLocalRef(iarr); } return result; } //创建一个二维int数组,并赋值完毕 注意: 以上使用的函数调用方式都是针对C++的,如果要用在C中,所有的env->都要被替换成(*env)->,而且后面的函数中需要增加一个参数env
访问Java类的域和方法 访问Java类的私有域和方法
public class ClassA{ String str="abcde"; int number; public native void nativeMethod(); private void javaMethod(){ System.out.println("call javaMethod successed"); } static{ System.loadLibrary("ClassA"); } } //C++实现 JNIEXPORT void JNICALL Java_testclass_ClassCallDLL_nariveMethod(JNIEnv *env,jobject obj){ //accessfield jclass cls =env->GetObjectClass(obj); //得到对象 jfieldID fid=env->GetFieldID(cls,"str","Ljava/lang/String;"); jstring jstr =(jstring)env->GetObjectField(obj,fid); const char *str=env->GetStringUTFChars(jstr,false); if(std::string(str)=="abcde") std::cout<<"accessfieldsuccesses"<<std::endl; //得到字符字段 jint i=2468; fid =env->GetFieldID(cls,"number","I"); env->SetIntField(obj,fid,i); //设置值 jmethodID mid=env->GetMethodID(cls,"javaMethod","()V"); env->CallVoidMethod(obj,mid); //调用不带参数的方法 }
在native方法中使用用户定义的类
使用自定义的类和使用Java的基础类(比如String)没有太大的区别,关键的一点是,如果要使用自定义类,首先要能访问类的构造函数。
jclass cls=env->FindClass("Ltestclass/ClassB"); //创建一个自定义类的引用 jmethodID mid=env->GetMethodID(cls,"<init>","(D)V"); //获得这个类的构造函数 jdouble dd=0.033; jvalue args[1]; args[0].d=dd; jobject obj=env->NewObjectA(cls,mid,args); //生成了一个ClassB的对象,args是ClassB的构造函数的参数,它是一个jvalue*类型。
异常处理
在native方法中发生了异常,传导到Java中
jclass Cls;env->ExceptionDescribe();env->ExceptionClear();errCls=env->FindClass("java/lang/IllegalArgumentException");env->ThrowNew(errCls,"thrownfromC++code");//如果要抛出其他类型的异常,替换掉FindClass的参数即可。这样,在Java中就可以接收native方法中抛出的异常。
类的相关操作
jclass FindClass(JNIEnv *env,const char *name); //查找类常见异常: ClassFormatError 类的数据格式无效 ClassCircularityError 该类或接口是自身的超类或超接口 NoClassDefFoundError 没有找到指定名称的类或接口 OOM 内存不足错误,即OutOfMemoryError
jclass GetSuperclass(JNIEnv *env,jclass clazz); //获取父类或者说超类 //第二个参数传入的是子类,否则返回将是NULL
jboolean IsAssignableFrom(JNIEnv *env,jclass clazz,jclass clazz2); //判断class1对象能否安全的强制转换为class2对象 /* 以下情况返回true: JNI_TRUE 1、这两个类参数引用同一个Java类 2、第一个类是第二个类的子类 3、第二个类是第一个类的某个接口
jclass GetObjectClass(JNIEnv *env,jobject obj); //通过对象获取这个类 //对象不能为NULL,否则获取的class肯定返回也为NULL
jboolean isInstanceOf(JNIEnv *env,jobject obj,jclass clazz); //判断对象是否为某一个类的实例 /* 注意: 返回值可能产生异议,就是如果传入的第二个参数为NULL对象,NULL对象可以强制转换为各种类,所有这种情况也将会返回JNI_TRUE,所以一定判断传入的对象是否为空。 */
jboolean IsSameObject(JNIEnv *env,jobject ref1,jobject ref2); //判断两个对象是否引用同一个类 /* 如果两个对象均为空,返回的值也会是JNI_TRUE所以使用时判断对象为空 */
调用Java方法:
jmethodID GetMethodID(JNIEnv *env,jclass clazz,const char *name,const char *sig); //获取一个Java方法的ID //这个函数将返回非静态类或接口实例方法的方法ID/*执行GetMethodID()函数将导致未初始化的类初始化,如果要获得构造函数的方法ID,使用<init>作为方法名,同时将void(V)作为返回类型,如果找不到指定的ID将返回NULL,同时异常可能有: NoSuchMethodError 找不到指定的Java方法。 ExceptionInInitializerError 如果由于异常而导致类初始化程序失败 OutOfMemoryError 内存不足*/
NativeType CallXXXMethod(JNIEnv *env,jobject obj,jmethodID methodID,va_list args); //调用XXX类型的Java方法/*执行Java类中的某个方法,需要注意的是这个里的java类是非静态的,由于Java的方法的类型比较多,所以该函数可能有以下几种形式,如:CallObjectMethod,CallBooleanMethod,CallByteMetod,CallCharMethod,CallShortMethod,CallIntMethod和CallVoidMethod,需要注意的是,该函数的第三个参数为通过GetMethodID函数获取的方法ID,最后一个参数为这个方法的参数表,最后的va_list宏可以通过搜索获取具体的使用方法。*/
NativeType CallNonvirtualXXXMethod(JNIEnv *env,jobject obj,jclass clazz,jmethodID methodID,jvalue *args); //与CallXXXMethod()不同之处是多了一个jclass参数,CallXXXMethod()是根据对象来调用方法,而CallNonvirtualXXXMethod是根据类的实例调用。
上面的三个均为非静态类的获取,执行调用,需要实例化这个类才可以执行,下面的为静态调用。
jmethodID GetStatic MethodID(JNIEnv *env,jclass clazz,const char *name,const char *sig);NativeType CallStatic XXXMethod(JNIEnv *env,jclass clazz,jmethodID methodID,...);
访问Java对象的域
jfieldID GetFieldID(JNIEnv *env,jclass clazz,const char *name,const char *sig); //获取实例对象的域ID /* 非静态的实例化后的对象,可能产生的异常有: NoSuchFieldError 找不到指定的域 ExceptionInInitializerError 因为异常而导致类初始化失败 OutOfMemoryError内存不足 */
NativeType GetXXXField(JNIEnv *env, jobject obj,jfieldID fieldID); //类似GetXXXMethod函数,可能有的类型有 GetObjectField,GetBooleanField,GetByteField,GetCharField,GetShortField,GetIntField,GetLongField
void SetXXXField(JNIEnv *env, jobject obj, jfieldID fieldID,NativeType value); //Java的域可以赋值的,可能有的类型有 SetObjectField,SetBooleanField,SetByteField,SetCharField,SetShortField,SetIntField,SetLongField
上面3种情况均为非静态对象的域,对于不需要实例化对象的域,可以直接使用下面的
jfieldID GetStaticFieldID(JNIEnv *env, jclass clazz,const char *name, const char *sig); jfieldID GetStaticFieldID(JNIEnv *env, jclass clazz,const char *name, const char *sig); void SetStaticXXXField(JNIEnv *env, jclass clazz,jfieldID fieldID, NativeType value);
0 0
- Android JNI编程规范
- android JNI编程技巧
- Android JNI 编程
- Android中JNI编程
- Android中JNI编程
- android JNI编程技巧
- android JNI 编程实例
- android JNI编程实例
- Android JNI编程实例
- Android中JNI编程
- Android JNI 编程
- Android JNI 编程
- android jni编程初步
- Android jni 编程
- android JNI 编程汇总
- Android JNI编程学习
- Android JNI编程指南
- android studio JNI编程
- mysql优化笔记
- leetcode:Populating Next Right Pointers in Each Node 【Java】
- Binary Tree Postorder Traversal
- 欢迎使用CSDN-markdown编辑器
- 20160307 Add Digits
- Android JNI编程规范
- android中JNI调用时内存分布以及内存泄露原因分析
- 【nova】centos7下libety版本openstack动态迁移虚拟机
- [译]使用注解处理器生成代码-3 生成源代码
- 第2章 jQuery之基础核心
- 五大常用算法之一--分治算法
- 《软件工程导论》——基本的软件开发过程模型
- sam-ba_2.15 使用usb Device 连接AT91SAM9261EK开发板
- mutex 和spin lock的区别