我有一个回调类,用于从 native C++ 代码到 Kotlin 的回调(不确定 Kotlin/Java 是否在这里有所作为,如果有,是否有相关文档?)。
我有一个带有整数参数的工作回调,我从不同的 native 线程调用它没有问题。现在我想添加第二个发送字符串,但由于某种原因不起作用。
我的回调类实现如下所示:
jclass target;
jmethodID id;
Callback::Callback(JavaVM &jvm, jobject object) : g_jvm(jvm), g_object(object) {
JNIEnv *g_env;
int getEnvStat = g_jvm.GetEnv((void **) &g_env, JNI_VERSION_1_6);
if (g_env != NULL) {
target = g_env->GetObjectClass(g_object);
id = g_env->GetMethodID(target, "integerCallback", "(I)V");
}
}
void Callback::call(int integerValue, const char *stringValue) {
JNIEnv *g_env;
int getEnvStat = g_jvm.GetEnv((void **) &g_env, JNI_VERSION_1_6);
if (getEnvStat == JNI_EDETACHED) {
if (g_jvm.AttachCurrentThread(&g_env, NULL) != 0) {
LOGD("GetEnv: Failed to attach");
}
} else if (getEnvStat == JNI_OK) {
LOGD("GetEnv: JNI_OK");
} else if (getEnvStat == JNI_EVERSION) {
LOGD("GetEnv: version not supported");
}
g_env->CallVoidMethod(g_object, id, (jint) integerValue);
}
它在我的
native-lib.cpp
中实例化像这样:extern "C" {
std::unique_ptr<Callback> callback;
JavaVM *g_jvm = nullptr;
static jobject myJNIClass;
jint JNI_OnLoad(JavaVM *pJvm, void *reserved) {
g_jvm = pJvm;
return JNI_VERSION_1_6;
}
JNIEXPORT void JNICALL
Java_com_my_app_common_jni_JniBridge_loadNative(JNIEnv *env, jobject instance,
jstring URI, jboolean isWaitMode) {
myJNIClass = env->NewGlobalRef(instance);
if (callback == nullptr) {
callback = std::make_unique<Callback>(*g_jvm, myJNIClass);
}
}
它与之对话的回调方法在我的
JniBridge.kt
中。 (线程部分可能与问题无关):object JniBridge {
init {
System.loadLibrary("native-lib")
Timber.d("Native Lib loaded!")
}
fun load(fileName: String, isWaitMode: Boolean) {
loadNative(fileName, isWaitMode)
}
fun integerCallback(value: Int) {
someListener?.invoke(value)
}
private external fun loadNative(fileName: String, isWaitMode: Boolean)
}
所以现在如果我的 native 代码触发
call()
我的回调中的方法,我的 integerCallback()
在 JniBridge.kt
用整数正确调用。但这是我没有得到的:如果我将回调更改为发送字符串,它就不起作用。如果我这样改变它:
// in JniBridge.kt
fun stringCallback(value: String) {
someListener?.invoke(value)
}
// in Callback.cpp
//getting the method
id = g_env->GetMethodID(target, "stringCallback", "(Ljava/lang/String)V");
//making the call
g_env->CallVoidMethod(g_object, id, (jstring) stringValue);
现在我的应用程序因此错误而崩溃:
JNI DETECTED ERROR IN APPLICATION: JNI GetStringUTFChars called with pending exception java.lang.NoSuchMethodError: no non-static method "Lcom/my/app/common/jni/JniBridge;.stringCallback(Ljava/lang/String)V"
如果我尝试调用
void
,也会发生同样的情况方法(像这样:id = g_env->GetMethodID(target, "voidCallback", "(V)V");
或调用一个需要两个整数的方法(像这样:id = g_env->GetMethodID(target, "twoIntegerCallback", "(I;I)V");
,当然在 JniBridge.kt
中有相应的方法。为什么会发生这种情况,我该如何解决?
注意:为清楚起见,我省略了我认为与问题无关的所有代码部分,如果缺少关键内容,请告诉我,我会修复它。
最佳答案
您在传递给 GetMethodID
的方法签名中缺少分号。 .
它应该是:
id = g_env->GetMethodID(target, "stringCallback", "(Ljava/lang/String;)V");
注意
Ljava/lang/String
后面的分号.请参阅 Oracle's JNI documentation 中有关类型签名的部分.
关于您的其他变体:
一个Java
void function()
会有签名()V
.一个Java
void function(int i, int j)
会有签名(II)V
.附带说明一下,您确实应该在每次 JNI 调用后验证返回值并检查异常。
关于android - Android : Callback from native with Integer parameter works, 上的 JNI 与 String 或 Void 它没有。为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61713422/