首先,让我列出我可以获取的最佳结果。 jni call java method which take a custom java interface as parameter
这不是我的回答。让我解释一下我的问题。我想按照以下方式打电话给NDK。
(1)Java - > (2)CPP - > (3)C(新线程) - > (4)CPP - > (5)的Java
代码如下。
(1)Java
public interface Callback<T> {
void success(T result);
}
private native void jniUploadAsync(String imagePath, Callback<String> callback);
jniUploadAsync(file.getAbsolutePath(), new Callback<String>() {
@Override
public void success(final String result) {
Log.v("MyClass: result:: ", result);
}
});
(2)CPP
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);
}
(3)C
CallMyCMethod() //please assume that it works. The reason I need void* as the type for completionCallback is because, in ObjC implementation I use this
(4)CPP
//Call comes back to imageUploadCallback()
(5)Java
//I expect this Log.v("MyClass: result:: ", result); to be executed
请注意,这不是关于如何从C ++调用Java的基本问题。我想解决的两个具体问题是,如何调用“回调”以及如何在Java接口实现中调用方法。我已经为Obj-C做了这个,直截了当。
答案 0 :(得分:4)
(2)
首先,您需要存储对JavaVM
的引用,以便稍后可以从其他线程获取JNIEnv
。此外,您需要从参数获取的局部变量获取新的全局引用(不要在不再需要时删除它,否则会导致内存泄漏)。
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);
}
(4)
使用泛型时,原生方无法知道它们的类型,因此您使用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();
}