JuiCe
JuiCe

Reputation: 4191

Calling a Java function from the Native code using the NDK

I asked this question the other day, but wasn't too specific, so I want to re-clarify.

I am creating an Android Application which uses an existing library in C using the NDK. The problem I have run into is that the C code uses a lot of things java doesn't ( function pointers as parameters is the big problem ).

Anyway, I was wondering if I could write functions in my Java code that the C code calls. Now from what I can tell, you can do it, so I would appreciate it if no one just answered 'Yes you can, LINK." I have been looking into it but its very over my head as to what actually needs to be done.

Can anyone try to explain the process? I know it involves creating a JVM in the C code; any information that will help a newbie get on his feet will be greatly appreciated.

Thanks

EDIT :

So, I don't know what to do for these three steps.

To call a specific Java function from C, you need to do the following:

Obtain the class reference using the FindClass(,,) method.
Obtain the method IDs of the functions of the class that you want to call using the 
GetStaticMethodID and GetMethodID function calls.

Call the functions using CallStaticVoidMethod, CallStaticIntMethod, and CallStaticObjectMethod.

This isn't explained too much and I have literally no experience in C. Is FindClass a C method?

Upvotes: 3

Views: 6141

Answers (1)

Seva Alekseyev
Seva Alekseyev

Reputation: 61331

Every C function that is callable from Java via JNI has a first parameter of type JNIEnv*. On the C end, this is a pointer to a pointer to a structure with a bunch of pointers to functions. Those functions are your interface to the Java world. FindClass, GetMethodID and the rest are among them.

So when you want to call FindClass from the C side, here's how you do it:

void Java_com_mypackage_MyClass_MyMethod(JNIEnv *jniEnv, jobject thiz)
{
    jclass *clazz = (*(*jniEnv)->FindClass)(jniEnv, "com/mypackage/SomeClass");
    jmethodID MethodID = (*(*jniEnv)->GetStaticMethodID)(jniEnv, clazz, "SomeMethod", "(I)I");
    int result = (*(*jniEnv)->CallStaticIntMethod)(jniEnv, clazz, MethodID, 18);

And so forth. The line dereferences the jniEnv parameter, gets a function pointer and calls the function through it. Class and method names are completely bogus, naturally. How would I know yours.

Note: I'm talking of function pointers here, but not in the same sense as you do; those are function pointers to functions that JNI provides, not to your functions.

The verbosity of call syntax has to do with the limitations of C; in C++, you can write instead

jclass *cl = jniEnv->FindClass("com/mypackage/SomeClass");

as C++ supports function table pointers of this sort natively via virtual functions.

You can probably take some shortcuts along the way. If you're calling methods in the same class as your C point of entry, and it happens to be static, your second parameter already is a class object pointer. If you have a this pointer to the object you want to invoke a method on, you can use GetObjectClass.

Upvotes: 4

Related Questions