ndk开发的过程中,Android(Java)与JNI(C/C++)之间,由于参数类型无法互通,所以在传参的过程中,会遇到不少的麻烦。
其中我感觉最麻烦的要数字符串类型的传参
从JAVA传字符串到C++
上层JAVA数据类型String对应NDK为jstring类型,上层传参的方式和普通的java函数间调用并没有什么区别,重点是底层函数,如何将上层传来的jstring转化成本地可认并且可以操作的char *数组
例子如下(函数封装,可由实际函数调用。返回的char *数组一定要在外部记得释放,否则会造成内存泄漏):
char *JavaStringToCStr(JNIEnv *env, jstring str) { char *result = NULL; // 先找到JAVA/String类 jclass strCls = env->FindClass("java/lang/String"); jstring encodeMothed = env->NewStringUTF("UTF8"); jmethodID java_getBytes = env->GetMethodID(strCls, "getBytes", "(Ljava/lang/String;)[B"); jbyteArray barr = (jbyteArray)env->CallObjectMethod(str, java_getBytes, encodeMothed); jsize length = env->GetArrayLength(barr); jbyte *ba = env->GetByteArrayElements(barr, JNI_FALSE); if (length > 0) { result = (char *)malloc(length + 1); memcpy(result, ba, length); result[length] = 0; env->ReleaseByteArrayElements(barr, ba, 0); } return result; }
主题思想:先将String转化成JAVA的字符串数组(对应java描述为byte[]
),再对byte进行字符串复制操作。
方法:
1、定位JAVA的String类
2、找到String类下面的函数getBytes
3、调用getBytes将字符串转化成jbyte
4、进行字符串复制操作
5、释放相关资源
从C++传字符串到java
从C++传字符串到java又分为两种形式
1、通过result返回值的方式
这种方式其实在使用的时候比较简单,如下即可:
return env->NewStringUTF("jni:string from jni");
2、通过回调的方式向JAVA传字符串
这种传值的方式就比较麻烦。回调的方法此处不谈,仅聊参数的传递
实例如下:
void Java_com_example_ndktest_JniCommon_toJniString(JNIEnv *env, jobject thiz, jstring str) { char*cStr = JavaStringToCStr(env, str); constchar *demo = "jni say:"; char*result = (char*)malloc(strlen(demo) +strlen(cStr) + 1); memset(result, 0,strlen(demo)+strlen(cStr)+1); strcpy(result, demo); if(cStr != NULL) { strcat(result, cStr); } jstring java_result = env->NewStringUTF(result); // 调用上层java jclass clazz = env->GetObjectClass(thiz); jclass cClazz = (jclass)env->NewGlobalRef(clazz); jmethodID ShowJniString = env->GetMethodID(cClazz,"ShowJniString", "(Ljava/lang/String;)V"); env->CallVoidMethod(thiz, ShowJniString, java_result); free(cStr); free(result); }
重点:其实回调的方式和普通函数的回调类似,重点在于env->GetMethodID这个函数的第三个参数写法。其中括号内代表参数,多个可以直接连续写下去。括号外代表返回值
( arg-types ) ret-type
开发过程中遇到的JAVA类型标识列表
标识 | 类型 | 举例 |
---|---|---|
J | long | ----- |
Z | boolean | ---- |
B | byte | ----- |
C | char | ----- |
S | short | ------- |
I | int | ----- |
F | float | ---- |
D | double | ------ |
Lclassname; | specify class | Ljava/lang/String; |
[type | type[] | 本文第一段代码:[B |