Реализовать функцию обратного вызова в JNI, используя интерфейс - PullRequest
16 голосов
/ 19 июля 2011

Мне нужно реализовать функцию обратного вызова в Java, используя «интерфейс».Я написал часть приложения как MyJavaFunction(int size, m_GetSizeInterface);

m_GetSizeInterface - это интерфейс, который содержит функцию обратного вызова GetSize.Этот метод GetSize переопределяется в приложении.В JNI мне нужно вызвать функцию CPP, имеющую прототип int MyCPPFunction(int size, int (*callback)(int* ID));

Как я могу передать этот GetSize в качестве параметра MyCPPFunction в JNI?Пожалуйста, помогите

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

Ответы [ 2 ]

16 голосов
/ 20 июля 2011

Сложность здесь в том, что вы хотите вызвать собственный код C ++, который вы, в свою очередь, хотите вызвать java-метод. Это на самом деле немного сложно.

Вам нужно создать функцию JNI C ++ для вызова java и сопоставления функций C ++ подпись обратного вызова MyCPPFunction. Последний будет выступать в качестве оболочки для вызова метода Java.

Поскольку оболочке потребуется информация о среде JNI, которая не может быть предоставлена ​​параметрами (чтобы мы не испортили подпись), вы создаете несколько глобальных переменных для ее хранения:

jobject g_getSizeIface;
jmethodID g_method;
JNIEnv *g_env;

Функция C ++, которую вызовет java, выглядит следующим образом:

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;
}
0 голосов
/ 02 июня 2016
#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);
...