2012-02-16 126 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