2012-02-16 7 views
4

Je suis coincé avec cela, j'ai besoin d'appeler une fonction Java de c/C++. Dans les exemples et les didacticiels, je ne vois qu'une application java appelant une méthode c, et dans cette même méthode appelant une autre méthode java, mais ce que je veux faire est d'appeler une méthode java à partir de n'importe quelle partie du code. Voilà ce que j'ai:Comment appeler la fonction Java de c

static JNIEnv mEnv; 
static jclass mClassAndroidActivity; 
static mMethodSayHello; 
JNIEXPORT void JNICALL JNI_FUNCTION(AndroidActivity_nativeInit)(JNIEnv* env, jobject obj, int width, int height) 
{ 
    mEnv = env; 
    jclass cls = (*env)->GetObjectClass(env, obj); 
    mClassAndroidActivity = (*env)->NewGlobalRef(env, cls); 
    mMethodSayHello = (*env)->GetMethodID (env, mClassAndroidActivity, "SayHello", "(Ljava/lang/String;)V"); 
} 

//this method is called from a cpp 
void nativeSayHello(char* msg) 
{ 
    jstring string = (*mEnv)->NewStringUTF(mEnv, msg); 
    (*mEnv)->CallVoidMethod(mEnv, mClassAndroidActivity, mMethodSayHello, string); 
} 

mais est toujours écraser, je l'ai essayé sans NewGlobalRef, en utilisant MENV au lieu d'env dans le JNI_Function, j'ai essayé d'obtenir l'identifiant de la méthode du JNI_OnLoad, mais se bloque toujours .

C'est le journal que je reçois:

02-15 18: 09: 48,520: W/dalvikvm (27904): JNI AVERTISSEMENT: threadid = 1 en utilisant env de threadid = 0

+0

'Le "meilleur" journal que je reçois dit que env du fil 1 était différent du fil 0' C'est correct, je crois. Vous devriez avoir un pointeur env différent par thread Java. – Yourpalal

+0

ouais mais comment puis-je enregistrer le premier pointeur env donc je peux utilisé dans différents threads –

Répondre

9

Vous pouvez » t réutilise JNIEnv car elle est spécifique au thread appelant. Pour appeler la méthode (non statique) Java à partir du code natif, vous avez besoin quelque chose comme ceci:

static JavaVM *gJavaVM; 
static jobject gCallbackObject = NULL; 

JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { 
    gJavaVM = vm; 
    return JNI_VERSION_1_6; 
} 

JNIEXPORT void JNICALL JNI_FUNCTION(AndroidActivity_nativeInit)(JNIEnv* env, jobject obj, int width, int height) { 
    // ... 
    gCallbackObject = (*env)->NewGlobalRef(env, obj); 
} 

JNIEXPORT void JNICALL JNI_FUNCTION(AndroidActivity_nativeRelease)(JNIEnv* env, jobject obj) { 
    (*env)->DeleteGlobalRef(env, gCallbackObject); 
    gCallbackObject = NULL; 
} 

//this method is called from native code 
void nativeSayHello(char* msg) { 
    int status; 
    JNIEnv *env; 
    int isAttached = 0; 

    if (!gCallbackObject) return; 

    if ((status = (*gJavaVM)->GetEnv(gJavaVM, (void**)&env, JNI_VERSION_1_6)) < 0) { 
     if ((status = (*gJavaVM)->AttachCurrentThread(gJavaVM, &env, NULL)) < 0) { 
      return; 
     } 
     isAttached = 1; 
    } 

    jclass cls = (*env)->GetObjectClass(env, gCallbackObject); 
    if (!cls) { 
     if (isAttached) (*gJavaVM)->DetachCurrentThread(gJavaVM); 
     return; 
    } 

    jmethodID method = (*env)->GetMethodID(env, cls, "SayHello", "(Ljava/lang/String;)V"); 
    if (!method) { 
     if (isAttached) (*gJavaVM)->DetachCurrentThread(gJavaVM); 
     return; 
    } 

    jstring string = (*mEnv)->NewStringUTF(mEnv, msg); 
    (*env)->CallVoidMethod(env, gCallbackObject, method, string); 

    if (isAttached) (*gJavaVM)->DetachCurrentThread(gJavaVM); 
} 

Cet extrait de code n'a pas été testé. Pour éviter les fuites de mémoire, n'oubliez pas d'appeler la méthode nativeRelease() dans votre code Java lorsque la référence à l'objet ne sera plus nécessaire.

Voir la documentation The Java Native Interface pour plus de détails.

+0

nice, ça marche, thnx –

+0

Cela fonctionne merveilleusement .. merci pour cela! – Bruce

Questions connexes