QAndroidJniObject调用Java方法取jlong报NoSuchMethodError如何解决
根因说明
Java侧getAmount()方法的返回值为装箱类型java.lang.Long,而非基本数据类型long,你调用时传入的方法签名()J对应的是返回基本long类型的方法,所以会触发方法找不到的异常。
基于QAndroidJniObject的解决方案
有两种可选实现:
- 方案1:修改Java侧代码,将返回值改为基本类型
long,原有C++调用逻辑无需调整
// Java侧修改后代码 public long getAmount() { return this.mAmount; }
- 方案2:不修改Java代码,调整C++侧调用逻辑,先获取装箱的
Long对象,再调用其longValue()方法转为基础jlong类型
static void onOperationStatusApprovedReceived(JNIEnv *env, jobject /*thiz*/,jobject statusObj) { QAndroidJniObject callbackObj(statusObj); qDebug()<<"mId"<<callbackObj.callObjectMethod<jstring>("getID").toString(); // 先获取装箱类型Long对象 QAndroidJniObject amountObj = callbackObj.callObjectMethod("getAmount", "()Ljava/lang/Long;"); // 调用Long类的longValue方法转成基本jlong类型 jlong amount = amountObj.callMethod<jlong>("longValue", "()J"); qDebug()<<"mAmount"<< amount; }
原生JNI extern C实现方案
完全可以使用原生JNI替代QAndroidJniObject实现需求,QAndroidJniObject本身就是对JNI接口的Qt封装,原生实现示例如下:
extern "C" JNIEXPORT void JNICALL // 注意方法名需按JNI规范,替换为你Java侧声明approvedStatusSendToQt方法的类全路径 Java_com_xxx_xxxx_approvedStatusSendToQt(JNIEnv *env, jclass thiz, jobject statusObj) { // 获取OperationData类引用 jclass cls_operation = env->FindClass("com/sim/lib/operation/OperationData"); // 调用getID方法 jmethodID mid_getId = env->GetMethodID(cls_operation, "getID", "()Ljava/lang/String;"); jstring id_jstr = static_cast<jstring>(env->CallObjectMethod(statusObj, mid_getId)); const char* id_cstr = env->GetStringUTFChars(id_jstr, nullptr); qDebug() << "mId" << QString::fromUtf8(id_cstr); env->ReleaseStringUTFChars(id_jstr, id_cstr); // 调用getAmount方法获取装箱Long对象 jmethodID mid_get_amount = env->GetMethodID(cls_operation, "getAmount", "()Ljava/lang/Long;"); jobject amount_obj = env->CallObjectMethod(statusObj, mid_get_amount); // 转基本jlong类型 jclass cls_long = env->FindClass("java/lang/Long"); jmethodID mid_long_value = env->GetMethodID(cls_long, "longValue", "()J"); jlong amount = env->CallLongMethod(amount_obj, mid_long_value); qDebug() << "mAmount" << amount; // 释放JNI局部引用,避免内存泄漏 env->DeleteLocalRef(cls_operation); env->DeleteLocalRef(id_jstr); env->DeleteLocalRef(amount_obj); env->DeleteLocalRef(cls_long); }
原生JNI实现需要注意手动管理JNI引用,方法命名需符合JNI规范(类路径的点替换为下划线,下划线、特殊字符需要转义)。
内容的提问来源于stack exchange,提问作者Artem Redko
相关产品推荐
相关产品推荐

