2011-06-01 52 views
11

在這裏我創建了一個JAVA類,其中我有必須從C文件中調用的函數(回調函數)。如何創建靜態JNI環境指針?

class DSMInitializeClassParameter { 

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

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

爲此,我創建了必須調用的本地方法。

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

Ç文件我有以下幾點:

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

你怎麼看我想打電話給(*env)->CallVoidMethod(env, classObject, mid);dsmInitializeCall功能,但我怎麼能叫,如果我沒有envclassObjectmid我嘗試使用靜態但不起作用。

回答

22

它通常是unsafe來緩存一個JNIEnv*實例並繼續使用它,因爲它根據當前活動的線程而變化。你可以保存一個JavaVM*實例,它永遠不會改變。在本地初始化函數,調用GetJavaVM,並將它傳遞一個JavaVM指針的地址:

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

現在你可以使用JavaVM*來獲取當前JNIEnv*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

非常感謝,我會在明天檢查我的工作場所......可能你可以幫助我解決這個問題嗎? http://stackoverflow.com/questions/6152747/jni-not-support-types-as-void-unsigned-int-what-to-do – 2011-06-01 20:04:14

+0

爲什麼我不能使用jclass cls =(* env) - > GetObjectClass( env,classObject);而不是jclass cls =(* env) - > FindClass(env,「com/Dsm/Test/DSMInitializeClassParameter」);我認爲classObject是我的類的對象,我有DSMInitializeCallback,所以我可以從該對象獲取類。但是,當我嘗試應用程序崩潰與Dalvic虛擬機錯誤....但爲什麼? – 2011-06-02 05:35:50

+0

http://stackoverflow.com/questions/6184678/where-can-i-see-message-from-jni-printf-in-eclipse – 2011-06-02 08:35:44

6

另一種方法來確保您獲得對JavaVM的參考,因爲第一個業務訂單是添加JNI_OnLoad方法並緩存參考。這將在共享庫加載時調用。

Ex。

static JavaVM* cachedJVM; 

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

一旦有裁判在JavaVM指針就可以使用在上述柱中描述的方法Michael Mrozek

+0

爲什麼它必須是靜態JavaVM *而不僅僅是JavaVM *?爲什麼它必須是靜態的? – pdiddy 2014-03-07 13:41:58

+0

爲了將JavaVM變量限制在聲明它的文件中。 – Gio 2015-09-19 22:26:21