【问题标题】:Implement callback function in JNI using Interface使用接口在 JNI 中实现回调函数
【发布时间】:2011-10-08 10:23:26
【问题描述】:

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

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

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

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

【问题讨论】:

    标签: java interface callback java-native-interface function-pointers


    【解决方案1】:

    这里的复杂之处在于您想要调用本机 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;
    }
    

    【讨论】:

    • 我们可以有完整功能的示例代码..在Java层声明什么?
    • 如果需要多次用原生代码注册回调(传递不同的接口实现),这样每个 WrapperFunc 注册都有一个关联的接口对象/方法来调用
    【解决方案2】:
    #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);
    

    【讨论】:

      猜你喜欢
      • 2015-02-05
      • 1970-01-01
      • 2021-07-21
      • 2012-09-05
      • 1970-01-01
      • 2019-12-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多