JNI初步入门后,在传递数据的时候,遇到一个需求:有多个数据需要在Java与C代码之间进行传递。如果都做为函数参数传入,则函数很长很难看,并且多个数据的返回也不好实现。所以想到了把数据打包后传递。这在C语言中就是结构体,在Java中就是类了。 我们要做的工作就是,先确定要传递的数据,然后相应在C与Java中定义相应的数据类型,然后通过JNI进行数据对应。下面以一个例程来逐步说明。
为了更好的说明各种数据类型的转换示例,我们的数据包含整型、字符串、浮点数、字符、布尔值、数组。
jni接口中并不要求两边的变量名一致,或者类名与结构体名一致,只是我们为了逻辑清晰,最好将名称定义的一致,以便于在后续编写代码的过程中更好的将相应数据一一对应起来。
其中,com/example/helloworld 是包名对应路径,ParamInfo是包含数据接口的类名。
获取类中一个整型变量intValue的定义 jfieldID jfi = env->GetFieldID(jcInfo, "intValue", "I"); 获取实例的变量intValue的值,其中jobj即参数中携带数据的对象: paramInfo.intValue = env->GetIntField(jobj, jfi);以传递结构体中一个整型值为例:
先设置结构体中整型值: paramInfo.intValue = 8; 获取Java中的实例类ParamInfo jclass jcInfo = env->FindClass("com/example/helloworld/ParamInfo");其中com/example/helloworld 是包名对应路径,ParamInfo是包含数据接口的类名。
获取类中一个整型变量intValue的定义 jfieldID jfi = env->GetFieldID(jcInfo, "intValue", "I"); 创建新的对象 jobject joInfo = env->AllocObject(jcInfo); 设置实例的变量intValue的值 env->SetIntField(joInfo, jfi, paramInfo.intValue); 最后返回该对象 return joInfo;其余数据类型值的访问,都是类似的步骤。注意 GetFieldID()的第3个参数的取值,是数据类型的签名标识,具体取值见下面表格:
请查看下表:
Java类型符号booleanZbyteBcharCshortSintIlongLfloatFdoubleDvoidVobject对象LClassName; L类名;Arrays[array-type [数组类型methods方法(argument-types)return-type (参数类型)返回类型知道这些了,就可以进行我们native代码的书写了,如下:
// Java 类向C结构体类型转换 JNIEXPORT jint JNICALL Java_com_example_helloworld_JniClient_setInfo (JNIEnv *env, jobject jo, jobject jobj) { ParamInfo paramInfo; //获取Java中的实例类ParamInfo jclass jcInfo = env->FindClass("com/example/helloworld/ParamInfo"); //获取类中每一个变量的定义 //boolean boolValue jfieldID jfb = env->GetFieldID(jcInfo, "boolValue", "Z"); //char charValue jfieldID jfc = env->GetFieldID(jcInfo, "charValue", "C"); //double charValue jfieldID jfd = env->GetFieldID(jcInfo, "doubleValue", "D"); //int intValue jfieldID jfi = env->GetFieldID(jcInfo, "intValue", "I"); //byte[] array jfieldID jfa = env->GetFieldID(jcInfo, "array", "[B"); //String str jfieldID jfs = env->GetFieldID(jcInfo, "str", "Ljava/lang/String;"); //获取实例的变量boolValue的值 paramInfo.boolValue = env->GetBooleanField(jobj, jfb); //获取实例的变量charValue的值 paramInfo.charValue = env->GetCharField(jobj, jfc); //获取实例的变量doubleValue的值 paramInfo.doubleValue = env->GetDoubleField(jobj, jfd); //获取实例的变量intValue的值 paramInfo.intValue = env->GetIntField(jobj, jfi); //获取实例的变量array的值 jbyteArray ja = (jbyteArray)env->GetObjectField(jobj, jfa); int nArrLen = env->GetArrayLength(ja); char *chArr = (char*)env->GetByteArrayElements(ja, 0); memcpy(paramInfo.array, chArr, nArrLen); //获取实例的变量str的值 jstring jstr = (jstring)env->GetObjectField(jobj, jfs); const char* pszStr = (char*)env->GetStringUTFChars(jstr, 0); strcpy(paramInfo.str, pszStr); //日志输出 LOGI("paramInfo.array=%s, paramInfo.boolValue=%d, paramInfo.charValue=%c\n", paramInfo.array, paramInfo.boolValue, paramInfo.charValue); LOGI("paramInfo.doubleValue=%lf, paramInfo.intValue=%d, paramInfo.str=%s\n", paramInfo.doubleValue, paramInfo.intValue, paramInfo.str); return 0; } // C结构体类型向Java 类转换 JNIEXPORT jobject JNICALL Java_com_example_helloworld_JniClient_getInfo (JNIEnv *env, jobject jo) { char chTmp[] = "Test array"; int nTmpLen = strlen(chTmp); //将C结构体转换成Java类 ParamInfo paramInfo; memset(paramInfo.array, 0, sizeof(paramInfo.array)); memcpy(paramInfo.array, chTmp, strlen(chTmp)); paramInfo.boolValue = true; paramInfo.charValue = 'B'; paramInfo.doubleValue = 2.7182; paramInfo.intValue = 8; strcpy(paramInfo.str, "Hello from JNI"); LOGI("paramInfo.array=%s, paramInfo.boolValue=%d, paramInfo.charValue=%c\n", paramInfo.array, paramInfo.boolValue, paramInfo.charValue); //获取Java中的实例类 jclass jcInfo = env->FindClass("com/example/helloworld/ParamInfo"); //获取类中每一个变量的定义 //boolean boolValue jfieldID jfb = env->GetFieldID(jcInfo, "boolValue", "Z"); //char charValue jfieldID jfc = env->GetFieldID(jcInfo, "charValue", "C"); //double doubleValue jfieldID jfd = env->GetFieldID(jcInfo, "doubleValue", "D"); //int intValue jfieldID jfi = env->GetFieldID(jcInfo, "intValue", "I"); //byte[] array jfieldID jfa = env->GetFieldID(jcInfo, "array", "[B"); //String str jfieldID jfs = env->GetFieldID(jcInfo, "str", "Ljava/lang/String;"); //创建新的对象 jobject joInfo = env->AllocObject(jcInfo); //给类成员赋值 env->SetBooleanField(joInfo, jfb, paramInfo.boolValue); env->SetCharField(joInfo, jfc, (jchar)paramInfo.charValue); env->SetDoubleField(joInfo, jfd, paramInfo.doubleValue); env->SetIntField(joInfo, jfi, paramInfo.intValue); //数组赋值 jbyteArray jarr = env->NewByteArray(nTmpLen); jbyte *jby = env->GetByteArrayElements(jarr, 0); memcpy(jby, paramInfo.array, nTmpLen); env->SetByteArrayRegion(jarr, 0, nTmpLen, jby); env->SetObjectField(joInfo, jfa, jarr); //字符串赋值 jstring jstrTmp = env->NewStringUTF(paramInfo.str); env->SetObjectField(joInfo, jfs, jstrTmp); return joInfo; }可以看出,java设置的数值,已经成功传递到C端;而C程序设置的数据,也成功回传到java端了。
转自:http://blog.csdn.net/lintax/article/details/51759270
http://download.csdn.net/detail/lintax/9559413