使用接口在JNI中实现回调函数

发布于 2024-11-25 04:00:50 字数 429 浏览 0 评论 0原文

我需要使用“接口”在Java中实现回调函数。我将应用程序部分编写为 MyJavaFunction(int size, m_GetSizeInterface);

m_GetSizeInterface 是一个包含回调函数 GetSize 的接口。此 GetSize 方法在应用程序中被重写。在 JNI 中,我需要调用具有原型的 CPP 函数 int MyCPPFunction(int size, int (*callback)(int* ID));

如何将此 GetSize 作为参数传递给 JNI 中的 MyCPPFunction?请帮忙

public int GetSize (m_SizeClass arg0)
{
    g_size = arg0.size;
        return 0;
}

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;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

最终幸福 2024-12-02 04:00:50

这里的复杂之处在于您想要调用本机 C++ 代码,而您又想要调用 java 方法。这其实有点棘手。

需要创建一个JNI C++函数供java调用,以及一个C++函数匹配
MyCPPFunction 回调签名。后者将充当调用 java 方法的包装器。

因为包装器需要有关 JNI 环境的信息,而这些信息不能通过参数提供(以免破坏签名),所以您创建了一些全局变量来保存它:

jobject g_getSizeIface;
jmethodID g_method;
JNIEnv *g_env;

java 将调用的 C++ 函数如下:

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);
}

包装器函数是因此:

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;
}

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;
}
最美的太阳 2024-12-02 04:00:50
#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;


};

//测试代码为:

 SimpleQueueEvent queueEvent;
    std::function<void(void)> func = [](){
        printf("native runnable..\n");
    };

    int evenId = queueEvent.queueEvent(func);
    queueEvent.nativeEventFunc(evenId);
#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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文