2012-02-16 92 views
4

我一直坚持这一点,我需要从c/C++调用Java函数。如何从c调用Java函数

在示例和教程中,我只看到一个调用c方法的java应用程序,并且在调用另一个java方法的同一方法中,但我想要做的是从代码的任何部分调用java方法。这是我有:

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

但总是崩溃,我已经试过没有NewGlobalRef,使用而不是在JNI_Function ENV MENV,我试着从JNI_OnLoad获得方法ID,但老是死机。

这是日志我得到:

02-15 18:09:48.520:W/dalvikvm(27904):JNI警告:从主题ID = 0

+0

'我得到的“最佳”日志说,从线程1的env是不同于线程0'我相信这是正确的。每个Java线程应该有不同的env指针。 – Yourpalal 2012-02-16 01:25:59

+0

是的,但我怎么能保存第一个env指针,所以我可以用在不同的线程 – 2012-02-16 01:31:12

回答

9

你可以”线程ID = 1的env使用不重用JNIEnv,因为它是特定于调用线程的。要调用(非静态)从Java本机代码方法,你需要的东西是这样的:

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

这段代码没有进行测试。为了防止内存泄漏,当不再需要对象的引用时,请不要忘记在Java代码中调用nativeRelease()方法。

有关更多详细信息,请参阅The Java Native Interface文档。

+0

不错,它的工作原理,thnx – 2012-02-16 03:23:35

+0

这工作奇妙..谢谢你! – Bruce 2014-08-10 13:23:36