2013-01-25 4 views
4

J'écris du code pour obtenir un thread généré pour appeler une méthode Java statique à partir de C++.JNI: Appel de GetStaticMethodID explose

Les bits qui appellent la méthode fonctionnent correctement s'ils sont placés dans un appel natif à partir de Java, mais pas à partir d'un thread avec un JNIEnv attaché.

J'ai mis un JavaVM * comme suit:

jint JNI_OnLoad(JavaVM* jvm, void* reserved) 
{ 
    LOGI("Setting Java Virtual Machine"); 

    ThreadJNIEnvironment::javaVM = jvm; 

    return JNI_VERSION_1_6; 
} 

Cela ne s'appelle.

Je Spawn puis un autre fil et de ce fil, je fais ce qui suit:

JNIEnv* env; 
jint ret = ThreadJNIEnvironment::javaVM->AttachCurrentThread(&env, NULL); 

LOGI("AttachCurrentThread returned %d", ret); 

jclass interfaceClass = env->FindClass("com/ecmsys/mcb/model/McbInterface"); 
jmethodID testMethod = env->GetStaticMethodID(interfaceClass, "Test", "()V"); 
env->CallStaticVoidMethod(interfaceClass, testMethod); 

AttachCurrentThread retourne 0.

GetStaticMethod explose mais avec l'erreur suivante:

Fatal signal 11 (SIGSEGV) at 0x0000002c (code=1)..... 

I juste ne peux pas voir ce que j'ai fait pour le contrarier ... oh attendez ... vous ne pouvez pas accéder aux classes d'application Java à partir d'un thread engendré sans faire un peu de mise en place ...

jint JNI_OnLoad(JavaVM* jvm, void* reserved) 
{ 
    LOGI("Setting Java Virtual Machine"); 
    ThreadJNIEnvironment::javaVM = jvm; 

    JNIEnv* env; 


    jvm->AttachCurrentThread(&env, NULL); 
    jclass mcbInterface = env->FindClass("com/ecmsys/mcb/model/McbInterface"); 
    ThreadJNIEnvironment::interfaceClass = env->NewGlobalRef(mcbInterface); 

    return JNI_VERSION_1_6; 
} 

Ensuite, faites ceci:

JNIEnv* env; 
jint ret = ThreadJNIEnvironment::javaVM->AttachCurrentThread(&env, NULL); 

LOGI("AttachCurrentThread retured %d", ret); 

if(ThreadJNIEnvironment::interfaceClass) 
{ 
    jmethodID testMethod = env-->GetStaticMethodID(static_cast<jclass>ThreadJNIEnvironment::interfaceClass), "Test", "()V"); 
    env->CallStaticVoidMethod(static_cast<jclass>(ThreadJNIEnvironment::interfaceClass), testMethod); 
} 


ThreadJNIEnvironment::javaVM->DetachCurrentThread(); 

Vous vivez et apprendre!

Répondre

4

Vérifiez les exceptions après avoir recherché interfaceClass (env->ExceptionCheck()), ou vérifiez simplement qu'il n'est pas NULL. Très probablement, la recherche de classe échoue. InterfaceClass est en effet NULL, merci.

+1

Il fonctionne bien lorsqu'il est appelé depuis un appel Java natif. Je vais travailler sur ce que je fais mal maintenant! –

+1

Il s'est avéré que j'avais besoin de créer une référence globale à ma classe d'interface lorsque JNI_OnLoad est appelée, puis de l'utiliser au lieu de la rechercher dans l'instance JNIEnv d'un nouveau thread. –

+3

Vous pouvez également mettre en cache l'ID de méthode (vous n'avez pas besoin d'une référence pour cela) et vous devez utiliser une référence globale faible pour la classe. Vous avez besoin de la référence parce que vous avez sur la référence de classe au-delà de la portée d'un seul appel JNI (la référence initiale que vous obtenez est une référence locale). – technomage