2012-09-14 16 views
27

Estoy almacenando JNIEnv en un global, así que puedo llamar a los métodos estáticos de java más tarde. Pero es necesario almacenar un puntero global en el JNIEnv, como lo haría con cualquier otro objeto Java, o es un caso especial que no requiere esto.Guardando una referencia global al entorno JNIEnv

JNIEnv* globalEnvPointer; 

[JNICALL etc] void init(JNIENv* env, [etc]) 
{ 
    //required? 
    globalEnvPointer = (JNIENv*) (env*)->GetGlobalRef(env, env); 
    //or is this OK? 
    globalEnvPointer = env; 
} 

Editar

estoy Bing un poco tonto aquí, todos los métodos que utilizarán globalEnvPointer, se invocan dentro de mi init porque mi init es en realidad el método de mi programa cmain, que ganó' volver hasta el final del programa. Tampoco estoy usando otros hilos en el programa c. Creo que esto simplifica la respuesta.

JNIEnv* globalEnvPointer; 

[JNICALL etc] void main(JNIENv* env, [etc]) 
{ 
    //required? 
    globalEnvPointer = (JNIENv*) (env*)->GetGlobalRef(env, env); 
    //or is this OK? 
    globalEnvPointer = env; 
    someMethod(); 
} 

void someMethod() 
{ 
    //use globalEnvPointer here 
} 

Respuesta

41

No puede almacenar en caché el puntero JNIEnv. Obtenga información al respecto here:

El puntero de interfaz JNI (JNIEnv) es válido solo en el hilo actual. Si otro hilo necesita acceder a Java VM, primero debe llamar a AttachCurrentThread() para conectarse a la VM y obtener un puntero de interfaz JNI. Una vez conectado a la VM, un subproceso nativo funciona como un subproceso Java ordinario que se ejecuta dentro de un método nativo. El hilo nativo permanece adjunto a la máquina virtual hasta que llama a DetachCurrentThread() para separarse.

Lo que puede hacer es almacenar en caché el puntero JavaVM en su lugar.

static JavaVM *jvm; 

[JNICALL etc] void init(JNIENv* env, [etc]) 
{ 
    jint rs = (*env)->GetJavaVM(env, &jvm); 
    assert (rs == JNI_OK); 
} 

Y a continuación, siempre que lo necesite a continuación JNIEnv puntero desde un contexto en el que no se da usted esto:

void someCallback() { 
    JNIEnv *env; 
    jint rs = (*jvm)->AttachCurrentThread(jvm, &env, NULL); 
    assert (rs == JNI_OK); 
    // Use the env pointer... 
} 

Pero cada vez que se llama a un método nativo de Java el puntero env a utilizar es dado :

JNIEXPORT jint JNICALL Java_package_Class_method(JNIEnv *env, jobject obj) { 
    // just use the env pointer as is. 
} 
+0

Todo es un hilo, ¿eso hace la diferencia? es decir, mi 'init' se llama en el mismo hilo que luego llamará a los métodos java estáticos. – weston

+0

Utilice siempre el puntero 'JNIEnv' que está entrando en la función C. Como en mi último ejemplo. – maba

+0

Por favor, vea mi edición, en su ejemplo, si 'Java_package_Class_method' llamó' someCallback', no necesitaría ir a través de 'JavaVM' ¿o sí? En efecto, esto es lo que estoy haciendo, simplemente usando un global en lugar de pasarlo a 'someCallback'. – weston

Cuestiones relacionadas