Implement callback function in JNI using Interface
I need to implement callback function in Java using “interface”开发者_如何学编程. I have wrote the application part as MyJavaFunction(int size, m_GetSizeInterface);
m_GetSizeInterface is an Interface which contains the callback function GetSize. This GetSize method is override in the application. In JNI I need to call a CPP function having prototype int MyCPPFunction(int size, int (*callback)(int* ID));
How can I pass this GetSize as parameter to MyCPPFunction in JNI? Please help
public int GetSize (m_SizeClass arg0)
{
g_size = arg0.size;
return 0;
}
The complication here is that you want to invoke native C++ code which you, in turn, want to invoke a java method. This is actually a bit tricky.
You need to create a JNI C++ function for java to call, and a C++ function matching the MyCPPFunction callback signature. The latter will act as a wrapper to call the java method.
Because the wrapper will need information about the JNI environment, which cannot be provided by parameters (lest we ruin the signature) you create a few global variables to hold it:
jobject g_getSizeIface;
jmethodID g_method;
JNIEnv *g_env;
The C++ function which java will call is the following:
JNIEXPORT void JNICALL Java_ClassName_MyCPPFunction
(JNIEnv *env, jint size, jobject getSizeInterface)
{
jclass objclass = env->GetObjectClass(getSizeInterface);
jmethodID method = env->GetMethodID(objclass, "GetSize", "(m_SizeClass)I");
if(methodID == 0){
std::cout << "could not get method id!" << std::endl;
return;
}
g_method = method;
g_getSizeIface = getSizeInterface;
g_env = env
MyCPPFunction(size, WrapperFunc);
}
And the wrapper function is thus:
int WrapperFunc(int *id)
{
jint retval;
//marshalling an int* to a m_SizeClass boogy-woogy.
...
g_env->ExceptionClear();
retval = g_env->CallIntMethod(g_getSizeIface, g_method,
/*marshalled m_SizeClass*/);
if(g_env->ExceptionOccurred()){
//panic! Light fires! The British are coming!!!
...
g_env->ExceptionClear();
}
return rvalue;
}
#include <functional>
#include <cstdlib>
#include <map>
class SimpleQueueEvent {
public:
SimpleQueueEvent(){};
~SimpleQueueEvent(){};
//for C++ code call
int queueEvent(std::function<void(void)> func){
int curTime = time(0) + rand() % 10000;
eventMaps.insert(std::map<int, std::function<void(void)>>::value_type(curTime, func));
return curTime;
//Call Java method to invoke method, such as
//env->FindClass("....");
//jmethodID method = env->FindMethod("onPostQueueEvent"...);
//env->InvokeVoidMethod();
//Java code like this..
// private void onPostQueueEvent(final int eventId){
// listener.PostQueueEvent(new Runnable() {
// public void run() {
// nativeEventFunc(eventId);
// }
// });
// private static native void nativeEventFunc(int eventId);
}
void nativeEventFunc(int eventId){
if(eventMaps.find(eventId) != eventMaps.end()){
std::function<void(void)> func = eventMaps.at(eventId);
func();
}
}
private:
std::map<int, std::function<void(void)>> eventMaps;
};
//and test code is:
SimpleQueueEvent queueEvent;
std::function<void(void)> func = [](){
printf("native runnable..\n");
};
int evenId = queueEvent.queueEvent(func);
queueEvent.nativeEventFunc(evenId);
精彩评论