2014-04-01 20 views
0

嗨我有jobjectArray(字符串數組)從Java層傳遞到JNI層。 我想在jni調用之間保持它的活躍狀態,所以我通過值複製它。但是一旦我在jni調用之間切換,數據就會被破壞。NDK:保持從java層傳遞的變量通過值複製

JNIEXPORT void JNICALL Java_com_package_class(JNIEnv *env, jobject jobj, ptr, jobjectArray ddls){ 
    int ddlCount = env->GetArrayLength(ddls); 
    const char **ddls1 = (const char**)malloc(ddlCount); 
    for (int i=0; i<ddlCount; i++) { 
     jstring str = (jstring) env->GetObjectArrayElement(ddls, i); 
     const char *rawStr = env->GetStringUTFChars(str, NULL); 
     ddls1[i] = copyByValue(rawStr); 
     env->ReleaseStringUTFChars(str,rawStr); 
    } 
    for(int i=0; i<ddlCount; i++){ 
      LOG("ddls1=%s", ddls1[i]); 
    } 
    //pass ddls1 to some class object 
} 
const char* copyByValue(const char* str) { 
    int size = strlen(str); 
    char* str1 = (char *) malloc((size+1)*sizeof(char)); 
    memcpy(str1, str, size); 
    str1[size] = '\0'; 
    return str1; 
} 

現在,當我失去這個JNI上下文中,數據(ddls1)被損壞。有時在更改JNI上下文之前,即使在打印時,它也會崩潰。

請讓我知道我在做什麼錯在這裏以及什麼是複製jni變量的最佳方法,以便在我們鬆散JNI上下文後它們不會被破壞。

+0

試圖弄清*什麼*被損壞或丟失:ddls1(無論你通過它,發佈的副本是短暫的),它指向的指針數組,或指向實際字符的指針的目標內存存儲。 –

回答

1

對於實際問題,這看起來像是一個極其複雜的解決方案,無論可能如何。爲什麼使用memcpy而不是strcpy?事實上,因爲這是C++而不是C,最安全和最乾淨的方法是使用std::vector<std::string>

std::vector<std::string> copies; 

// ... 

char const *rawStr = env->GetStringUTFChars(str, NULL); 
std::string const copy(rawStr); 
env->ReleaseStringUTFChars(str, rawStr); 

現在你可以放心地使用copy對象;所有低級別的東西已經爲您處理。

copies.push_back(copy); 

請讓我知道我做錯了什麼是 副本JNI變量,最好的辦法,使他們不會成爲後我們失去 JNI上下文損壞。

您正在使用指針並忽略標準C++類。

我會將copies對象存儲在靜態C++變量中。當然,如果JNI函數被不同的線程使用,那麼你可能會遇到併發問題,所以如果你使用多線程,那麼要小心。

一個完全不同的解決方案是隻存儲原始對象的Java和C++每次你需要它的時候訪問它,通過回調到Java使用GetMethodIDGetFieldID

+0

謝謝,這個解決方案已經運行良好。我已經有了這個解決方案,但只是想知道使用const char **時出了什麼問題。如果可能,請告訴我們原始解決方案中的任何技術缺陷。 – bpsingh