2011-09-12 162 views
5

我有一個JNI問題,希望有人能幫助我。
我想從本地線程調用一個名爲LUSOutputJNI的Java類的構造函數。
它在這個特定類的FindClass(...)上保持失敗。無法使用JNI從本地線程調用Java方法(C++)

下面是代碼:

LOGE("1"); 
    JNIEnv *env = NULL; 

    LOGE("2"); 
    int res = -1; 
    res = g_vm->AttachCurrentThread(&env, NULL); 

    if(env == NULL) 
    { 
     LOGE("env is NULL, AttachCurrentThread failed");; 
    } 


    if(res >= 0) 
     LOGE("AttachCurrentThread was successful"); 
    jclass clazz = NULL; 
    jmethodID cid; 

    jclass clazzESEngine; 
    jmethodID callbackid; 

    jobject jCoreOut; 
    static jfieldID fid_ActionState = NULL; 
    static jfieldID fid_nSpeed = NULL; 
    static jfieldID fid_nType = NULL; 
    static jfieldID fid_nInProcess = NULL; 
    static jfieldID fid_nX = NULL; 
    static jfieldID fid_nY = NULL; 
    LOGE("3"); 

    static const char* const ECOClassName = "lus/android/sdk/LUSOutputJNI"; 
    //static const char* const ECOClassName = "android/widget/TextView"; 
    clazz = env->FindClass(ECOClassName); 
    if (clazz == NULL) { 
     LOGE("Can't find class LUSOutputJNI"); 

    } 
    else 
     LOGE("lus/android/sdk/LUSOutputJNI was found, YEY!!"); 

    LOGE("4"); 
    cid = env->GetMethodID(clazz,"<init>", "()V"); 
    LOGE("5"); 
    jCoreOut = env->NewObject(clazz, cid); 

    LOGE("6");  

下面是它失敗時輸出的logcat:

E/lusCore_JNI(3040): 1 
E/lusCore_JNI(3040): 2 
E/lusCore_JNI(3040): AttachCurrentThread was successful 
E/lusCore_JNI(3040): 3 
E/lusCore_JNI(3040): Can't find class LUSOutputJNI 
E/lusCore_JNI(3040): 4 
W/dalvikvm(3040): JNI WARNING: JNI method called with exception raised 

觀察:

  • 我得到的結果AttachCurrentThread是0,whic h表示該附件成功+ env指針不再爲NULL。
  • 我肯定LUSOutputJNI的包名聲明(三重檢查它...)
  • 當我嘗試用一​​種比較流行的類名運行的findClass(..)如Android /空間/ TextView的,我獲得積極的匹配。它在那裏。這意味着線程附件和env變量都可以。 (我能假設嗎?)
  • 當我嘗試從一個JNI方法運行下面的代碼時,它有一個JNI線程運行它,它發現LUSOutputJNI類沒有問題。

我在做什麼錯?

幫助將非常感激:)

感謝您的時間,

伊達

+0

對此'LUSOutputJNI'類的任何引用? –

+0

@ K-ballo:這可能是一個內部課程。 –

+0

@Ita:您的LUSOutputJNI靜態初始化程序是否引發異常?您應該打印引發的異常。 –

回答

6

找到答案\解決在這裏。 (尋找常見問題:「FindClass沒有找到我的課程」 JNI tips

我basicaly保存了一個全局引用到所需的jclass對象。
但是爲了編譯代碼,不得不克服一些C/JNI和C++/JNI之間的JNI變化。
這就是我如何得到NewGlobalRef編譯和工作。

jclass localRefCls = env->FindClass(strLUSClassName); 
if (localRefCls == NULL) { 
    LOGE("Can't find class %s",strLUSCoreClassName); 
    return result; 
} 

//cache the EyeSightCore ref as global 
/* Create a global reference */ 
clazzLUSCore = (_jclass*)env->NewGlobalRef(localRefCls); 

/* The local reference is no longer useful */ 
env->DeleteLocalRef(localRefCls); 

/* Is the global reference created successfully? */ 
if (clazzLUSCore == NULL) { 
    LOGE("Error - clazzLUSCore is still null when it is suppose to be global"); 
    return result; /* out of memory exception thrown */ 
} 

我希望這可以幫助任何人。

+0

謝謝,這有助於。這裏真的有必要刪除本地裁判嗎?我相信當函數返回時它們會自動刪除:http://android-developers.blogspot.co.il/2011/11/jni-local-reference-changes-in-ics.html – snowdragon

2

爲了得到更多的信息關於怎麼回事錯了(它會記錄到標準錯誤,未LOGE和我不知道如何改變這種狀況),你可以添加一些例外印刷 - 你可以改變這一點:

//static const char* const ECOClassName = "android/widget/TextView"; 
clazz = env->FindClass(ECOClassName); 
if (clazz == NULL) { 
    LOGE("Can't find class LUSOutputJNI"); 

} 
else 
    LOGE("lus/android/sdk/LUSOutputJNI was found, YEY!!"); 

要這樣:

//static const char* const ECOClassName = "android/widget/TextView"; 
    clazz = env->FindClass(ECOClassName); 
    if (clazz == NULL) { 
     LOGE("Can't find class LUSOutputJNI"); 
     jthrowable exc = env->ExceptionOccurred(); 
     if(exc) 
     { 
      env->ExceptionDescribe(); 
      env->ExceptionClear(); 
     }  
    } 
    else 
     LOGE("lus/android/sdk/LUSOutputJNI was found, YEY!!"); 
+1

看起來您可以使用jthrowable中的toString函數獲取錯誤信息,然後將其轉換爲C字符串並將其放入您的'LOGE'函數中,但這對於調試這可能是矯枉過正。 –