Android ndk 使用接口对Java进行JNI回调
首先,让我列出我能得到的最好结果。 这不符合我的要求。让我解释一下我的问题。我想打电话给NDK如下 (1) Java->(2)CPP->(3)C(新线程)->(4)CPP->(5)Java 代码如下 (1) 爪哇 (4) CPP (5) 爪哇 请注意,这不是一个关于如何从C++调用java的基本问题。我想解决的两个具体问题是,如何调用“回调”以及如何在Java接口实现中调用方法。我为Obj-C做了这项工作,它是直接向前的。(2) 首先,您需要存储对Android ndk 使用接口对Java进行JNI回调,android-ndk,java-native-interface,Android Ndk,Java Native Interface,首先,让我列出我能得到的最好结果。 这不符合我的要求。让我解释一下我的问题。我想打电话给NDK如下 (1) Java->(2)CPP->(3)C(新线程)->(4)CPP->(5)Java 代码如下 (1) 爪哇 (4) CPP (5) 爪哇 请注意,这不是一个关于如何从C++调用java的基本问题。我想解决的两个具体问题是,如何调用“回调”以及如何在Java接口实现中调用方法。我为Obj-C做了这项工作,它是直接向前的。(2) 首先,您需要存储对JavaVM的引用,以便以后能够从其他线程获取
JavaVM
的引用,以便以后能够从其他线程获取JNIEnv
。此外,您还需要从从参数中获取的局部变量中获取新的全局引用(当不再需要时,请不要忘记将其删除,否则将导致内存泄漏)
(四)
当使用泛型时,本机端不知道它们是什么类型的,所以无论您在哪里使用t
,都应该在JNI/C/CPP部分使用Object
您正在用C启动新线程。如果您愿意从该线程启动回调,则需要将其连接到java虚拟机,然后将其分离。根据我的理解,回调对象只使用一次。在这种情况下,还需要删除对它的全局引用
void imageUploadCallback(char *json, void *completionCallback) {
JNIEnv* env;
jvm->AttachCurrentThread(&env, NULL);
jclass cbClass = env->FindClass("org/winster/test/Callback");
jmethodID method = env->GetMethodID(cbClass, "success", "(Ljava/lang/Object;)V");
jstring abcd = env->NewStringUTF("abcd");
env->CallVoidMethod(completionCallback, method, abcd);
env->DeleteGlobalRef(completionCallback);
jvm->DetachCurrentThread();
}
您遇到了什么错误?不清楚
env
在imageUploadCallback
中来自何处。很可能需要调用AttachCurrentThread
。JNI在应用程序中检测到错误:使用了无效的jobject。这是我在尝试调用“回调”时遇到的错误对不起,这没有帮助。当然,我缓存环境;我想这会被理解的。正如所指出的,我在这里试图解决的问题是;当以接口为类型的实例时,如何在Java中调用回调。调用常规类方法并从本机线程调用它们是很容易解决的问题。您不能缓存env它只对该线程有效(对于当前jni调用的持续时间?),您必须从jvm获得它(您可能知道它,但编写了env而不是jvm)。从您的主要帖子上的评论中,我看到了错误:您从jni调用获得的对jobject的引用是本地的,您需要在存储它以供以后使用之前进行全局引用。我更新了关于如何缓存jvm的代码。我现在尝试的一个可能的选择是仅用Java保存回调。但是我必须把“作业项目”从CPP传给C。你知道怎么做吗?我想一个指针可能会对我有所帮助。我还在jni中添加了使用全局引用,我之前忘记了这一点。如果您在评论中提到的使用无效的jobject
仍然不起作用,则应该是这种情况。2对示例代码的更改。1) 我使用了“&”CallMyCMethod((char*)filePath、&imageUploadCallback、&globalref),而不是(void*);2) 从void*env->CallVoidMethod(static_cast(completionCallback)、callback_mid、jsonString)强制转换回jobject;同一错误“使用无效的jobject”
static JavaVM *jvm;
void imageUploadCallback(char *json, void *completionCallback) {
JNIEnv *env;
jint rs = jvm->AttachCurrentThread(&env, NULL);//create JNIEnv from JavaVM
jclass cbClass = env->FindClass("org/winster/test/Callback");
jmethodID method = env->GetMethodID(cbClass, "success", "(Ljava/lang/String;)V");
env->CallVoidMethod(static_cast<jobject>(completionCallback), method, "abcd");
}
void Java_org_winster_test_MyClass_jniUploadAsync(JNIEnv * env, jobject obj, jstring imagePath, jobject completionCallback) {
jint rs = env->GetJavaVM(&jvm); //Cache JavaVM here
CallMyCMethod((char *)filePath, &imageUploadCallback, &completionCallback);
}
CallMyCMethod() //please assume that it works. The reason I need void* as the type for completionCallback is because, in ObjC implementation I use this
//Call comes back to imageUploadCallback()
//I expect this Log.v("MyClass: result:: ", result); to be executed
static JavaVM* jvm = 0;
void Java_org_winster_test_MyClass_jniUploadAsync(JNIEnv * env, jobject obj, jstring imagePath, jobject completionCallback) {
env->GetJavaVM(&jvm); //store jvm reference for later
jobject globalref = env->NewGlobalRef(completionCallback);
CallMyCMethod((char *)filePath, &imageUploadCallback, (void *)globalref);
}
void imageUploadCallback(char *json, void *completionCallback) {
JNIEnv* env;
jvm->AttachCurrentThread(&env, NULL);
jclass cbClass = env->FindClass("org/winster/test/Callback");
jmethodID method = env->GetMethodID(cbClass, "success", "(Ljava/lang/Object;)V");
jstring abcd = env->NewStringUTF("abcd");
env->CallVoidMethod(completionCallback, method, abcd);
env->DeleteGlobalRef(completionCallback);
jvm->DetachCurrentThread();
}