First of all, let me list the best result I could fetch. jni call java method which take a custom java interface as parameter
This does not answer mine. Let me explain my problem. I want to make a call to NDK as follows.
(1)Java -> (2)CPP -> (3)C (new thread) -> (4)CPP -> (5)Java
Code is below.
(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
Please note that, this is not a basic question about how to call Java from C++. The 2 specific points I want to resolve is, how to call the "callback" and how to invoke a method in a Java Interface implementation. I have done this for Obj-C where it is straight forward.
Introduction At times, it is necessary to use native (non-Java) codes (e.g., C/C++) to overcome the memory management and performance constraints in Java. Java supports native codes via the Java Native Interface (JNI). JNI is difficult, as it involves two languages and runtimes. I shall assume that you are familiar with: Java.
Callback using Interfaces in Java 1 Create an interface ClickEventHandler with a single method handleClick (). 2 Create a ClickHandler class which implements this interface ClickEventHandler. 3 Create a Button class which will call ClickHandler when it's click method is called. 4 Test the application. More ...
To callback a static method, use GetStaticMethodID (), CallStatic<Primitive-type>Method (), CallStaticVoidMethod () or CallStaticObjectMethod (). The JNI functions for calling back instance method and static method are:
The naming convention for the C function is Java_ {package_and_classname}_ {function_name} (JNI_arguments). The dot in package name is replaced by underscore. The arguments are: JNIEnv*: reference to JNI environment, which lets you access all the JNI functions.
(2)
First of, you need to store reference to JavaVM
so you will be able to obtain JNIEnv
later from other thread. Also you need to get new global reference from local variable got from parameter (don't forgot to delete it when it is no longer needed, or it will cause memory leak).
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)
When using generics, native side can't know what type they are of, so everywhere you are using T
you should be using Object
on the JNI/C/CPP part
you are starting new thread in C. If you are willing to fire callback from that thread, you need to connect it to the java virtual machine and detach it afterwards. From what i think you do, you use the callback object only once. In that case you also need to delete global ref to it.
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();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With