调用静态 JNI 方法以从C++返回字符串
call a static JNI method to return a String from C++
我正在尝试在Android中调用以下java方法
public static String getLevelFile(String levelName) { /*body*/}
从 C++ 使用以下 JNI 代码
JniMethodInfoJavaApi methodInfo;
if (! getStaticMethodInfo(methodInfo, "getLevelFile", "(Ljava/lang/String;)Ljava/lang/String;"))
{
return std::string("");
}
LOGD("calling getLevelFile");
jstring returnString = (jstring) methodInfo.env->CallStaticObjectMethod(methodInfo.classID, methodInfo.methodID, levelName.c_str());
LOGD("returned from getLevelFile");
methodInfo.env->DeleteLocalRef(methodInfo.classID);
const char *js = methodInfo.env->GetStringUTFChars(returnString, NULL);
std::string cs(js);
methodInfo.env->ReleaseStringUTFChars(returnString, js);
LOGD("returning Level data");
执行CallStaticMethodObject()
时应用程序崩溃。我已经通过使用javap
验证了方法签名是否正确。LOGD("calling getLevelFile");
打印正常,然后崩溃。我可以做同一类的其他CallStaticVoidMethod()
,但不能做这个。知道我做错了什么吗?
你很幸运,Java和Android都使用Unicode字符集。但是,Android(默认情况下)使用UTF-8编码,JNI本质上不支持这种编码。尽管如此,Java 类完全能够在字符集编码之间进行转换。lang.java.String
构造函数允许您指定字符集/编码或使用操作系统默认值,当然,在 Android 上,它被编码为 UTF-8。
为了简化它(我更喜欢用 Java 编码,最大限度地减少调用 JNI 库的代码),创建方法的重载并在 Java 中执行一些实现:
private static byte[] getLevelFile(byte[] levelName) {
return getLevelFile(new String(levelName)).getBytes();
}
现在 JNI 代码只需要处理 jbytearray,无论是参数还是返回值:
JniMethodInfoJavaApi methodInfo;
if (! getStaticMethodInfo(methodInfo, "getLevelFile", "([B)[B"))
{
return std::string("");
}
LOGD("calling getLevelFile");
int nameLength = levelName.length();
jbyteArray nameBytes = methodInfo.env->NewByteArray(nameLength);
methodInfo.env->SetByteArrayRegion(nameBytes, 0, nameLength, reinterpret_cast<const jbyte*>(levelName.c_str()));
jbyteArray returnString = (jbyteArray) methodInfo.env->CallStaticObjectMethod(methodInfo.classID, methodInfo.methodID, nameBytes);
LOGD("returned from getLevelFile");
methodInfo.env->DeleteLocalRef(methodInfo.classID);
methodInfo.env->DeleteLocalRef(nameBytes);
int returnLength = methodInfo.env->GetArrayLength(returnString);
std::string data;
data.reserve(returnLength);
methodInfo.env->GetByteArrayRegion(returnString, 0, returnLength, reinterpret_cast<jbyte*>(&data[0]));
methodInfo.env->DeleteLocalRef(returnString);
LOGD("returning Level data");
return data;
你不能直接将 null 终止的字符串(从 c_str()
返回)作为参数传递给 Java/JNI 方法。
若要将其传递给方法,请从 null 终止的字符串创建一个jstring
(例如使用 NewStringUTF
),然后改为传递该字符串。
相关文章:
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- 什么时候在C++中返回常量引用是个好主意
- 你能重载对象变量名本身返回的内容吗
- 为什么 Serial.println(<char[]>);返回随机字符?
- C++映射:具有自定义类的运算符[]不起作用(总是返回0)
- 如何获取std::result_of函数的返回类型
- QueryWorkingSet总是返回false
- (C++)分析树以计算返回错误值的简单算术表达式
- 访问者访问变体并返回不同类型时出错
- 如何返回一个类的两个对象相加的结果
- OpenInventor从9.8升级到10.4.2后,GLSL纹理返回零
- lower_bound()返回最后一个元素
- "throw expression code" 1e7 >返回 d 是什么?投掷标准::overflow_error( "too big" ) : d;意味 着?
- 奇怪的(对我来说)返回声明 - 在谷歌上找不到任何关于它的信息
- 如何取消对nullptr的屏蔽,返回正确的对象
- 奇怪的结构&GCC&clang(void*返回类型)
- 架构决策:返回std::future还是提供回调
- 从python中调用C++函数并获取返回值
- 矩阵向量乘法(cublasDgemv)返回零
- 为什么模板类中的对象不能返回值