2011-06-01 27 views
11

Aquí creo una clase en JAVA en la que tengo una función (devolución de llamada) a la que debo llamar desde el archivo C.Cómo crear un indicador de entorno JNI estático?

class DSMInitializeClassParameter { 

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

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

Para eso he creado el método nativo que debe llamarse.

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

En archivo C He siguientes:

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

cómo se puede ver que quiero llamar (*env)->CallVoidMethod(env, classObject, mid); de dsmInitializeCall función, pero la forma en que se puede llamar si no tengo env, classObject y mid Intento con estática pero no funciona.

Respuesta

22

Generalmente es unsafe para almacenar en caché una instancia de JNIEnv* y seguir utilizándola, ya que varía según la secuencia actualmente activa. Usted puede guardar una instancia de JavaVM*, que nunca cambiará. En una función de inicialización nativa, llame GetJavaVM y pasarlo la dirección de un JavaVM puntero:

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

Ahora puede utilizar esa JavaVM* para obtener la corriente JNIEnv* con 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); 
} 
+0

Muchas gracias, revisaré mañana en mi lugar de trabajo ... ¿Y puede ser que me pueden ayudar en esta cuestión? http://stackoverflow.com/questions/6152747/jni-not-support-types-as-void-unsigned-int-what-to-do –

+0

Y por qué no puedo usar jclass cls = (* env) -> GetObjectClass (env, classObject); En lugar de jclass cls = (* env) -> FindClass (env, "com/Dsm/Test/DSMInitializeClassParameter"); Creo que classObject es un objeto de mi clase en el que tengo DSMInitializeCallback, así que puedo obtener clases de ese objeto. Pero cuando intento la aplicación se colgó con Dalvic VM Error ... ¿Pero por qué? –

+0

http://stackoverflow.com/questions/6184678/where-can-i-see-message-from-jni-printf-in-eclipse –

6

Otra manera de asegurar que obtenga una referencia a JavaVM ya que la primera orden del día es agregar el método JNI_OnLoad y almacenar en caché la referencia. Se llamará a esto cuando se cargue la biblioteca compartida.

Ej.

static JavaVM* cachedJVM; 

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

Una vez que tenga el árbitro JavaVM el puntero a continuación, puede utilizar el método Michael Mrozek se describe en el post anterior.

+0

¿Por qué tiene que ser JavaVM * estático y no solo JavaVM *? ¿Por qué tiene que ser estático? – pdiddy

+0

Para limitar la variable JavaVM al archivo dentro del cual se declara. – Gio

Cuestiones relacionadas