Как создать статическую JNI Environment Pointer? - PullRequest
10 голосов
/ 01 июня 2011

Здесь я создаю класс в JAVA, в котором у меня есть функция (обратный вызов), которую я должен вызывать из файла C.

class DSMInitializeClassParameter {

    /**
     * Callback function for DSM Initialize.
     */
    public void DSMInitializeCallback( ) {

        // Write Message To Logs.
        System.out.println( "Dsm Initialize Callback called." );
    }
}

Для этого я создал собственный метод, который должен быть вызван.

public class DsmLibraryTest extends Activity {
     // Some code ....

     // Create a DSMInitializeClassParameter  class object.
     DSMInitializeClassParameter object = new DSMInitializeClassParameter();
     // Call native method with given object.
     nativeMethod( object );

     // Some code ....

     // Implementation of native method.
     public native int nativeMethod(DSMInitializeClassParameter classObject);
}

В C файле у меня есть следующие данные:

dsmResult_t dsmInitializeCall( dsmResult_t status, void * pUserData, dsmEvent_t * hEvent ) {

    (*env)->CallVoidMethod(env, classObject, mid);
}

JNIEXPORT jint JNICALL Java_com_Dsm_Test_DsmLibraryTest_nativeMethod(JNIEnv* env, jobject obj, jobject classObject) {
    // This function loads a locally-defined class. It searches the directories and zip
    // files specified by the CLASSPATH environment variable for the class with the specified name.
    jclass cls = (*env)->FindClass( env, "com/Dsm/Test/DSMInitializeClassParameter" );
    // Get java Method.
    jmethodID mid = (*env)->GetMethodID(env, cls, "DSMInitializeCallback", "()V");
    // If no method was found return -1;
    if( mid == NULL ) {
        return -1;
    }

    // Call DSM Initialize Callback Function and return value.
    return dsmInitialize( dsmInitializeCall, NULL );
}

как вы видите, я хочу вызвать (*env)->CallVoidMethod(env, classObject, mid); из dsmInitializeCall функции, но как я могу вызвать ее, если у меня нет env, classObject и mid Я пытаюсь со статикой, но это не работает

Ответы [ 2 ]

24 голосов
/ 01 июня 2011

Обычно небезопасно кешировать экземпляр JNIEnv* и продолжать его использовать, поскольку он варьируется в зависимости от текущего активного потока.Вы можете сохранить экземпляр JavaVM*, который никогда не изменится.В собственной функции инициализатора вызовите GetJavaVM и передайте ей адрес указателя JavaVM:

static JavaVM *jvm;
JNIEXPORT void JNICALL Java_SomeClass_init(JNIEnv *env, jclass) {
    int status = (*env)->GetJavaVM(env, &jvm);
    if(status != 0) {
        // Fail!
    }
}

Теперь вы можете использовать этот JavaVM* для получения текущего JNIEnv* с помощью AttachCurrentThread:

dsmResult_t dsmInitializeCall( dsmResult_t status, void * pUserData, dsmEvent_t * hEvent ) {
    JNIEnv *env;
    (*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL);
    (*env)->CallVoidMethod(env, classObject, mid);
}
7 голосов
/ 08 июня 2012

Другой способ убедиться, что вы получаете ссылку на JavaVM в качестве первого шага, - это добавить метод JNI_OnLoad и кэшировать ссылку. Это будет вызвано, когда общая библиотека будет загружена.

Ex.

static JavaVM* cachedJVM;

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved)
{
    cachedJVM = jvm;
    // ... Any other initialization code.
}

Получив ссылку на указатель JavaVM, вы можете использовать метод Michael Mrozek , описанный в посте выше.

...