«NoSuchMethodError» при инициализации объекта из pthread - PullRequest
2 голосов
/ 05 марта 2012

У меня есть приложение для Android / Java, которое вызывает код C ++ через JNI для запуска операции блокировки.Код C ++ запускает поток для выполнения этой операции блокировки, которая после завершения должна вызывать JNI.

Вызов C ++ работает без проблем.Однако при обратном вызове JNI сообщается о множестве ошибок.

Получение ссылки jclass из нового потока, по-видимому, недопустимо.Выполнение этого действия приводит к «непредсказуемому поведению», поэтому все классы выполняются в методе JNI_OnLoad() и выглядят так:

static jclass sampleClazz;

jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
    jvm = vm;

    JNIEnv* env = NULL;
    jint result = jvm->GetEnv((void**)&env, JNI_VERSION_1_6);

    if(env == NULL) { __android_log_print(ANDROID_LOG_DEBUG, "JNI_OnLoad", "NULL");}

    sampleClazz= env->FindClass("com/sample/SampleClazz");
    sampleClazz= (jclass) env->NewGlobalRef(sampleClazz);

    ...etc...
}

В одном из этих потоков я пытаюсь вызвать обратно Javaкод.Метод обратного вызова выглядит примерно так:

void cCallBackOne() {
    JNIEnv* env;
    jvm->AttachCurrentThreadAsDaemon(&env, NULL);

    jmethodID init = env->GetMethodID(sampleClazz, "<init>", "()V");
    if(init == NULL) { 
        __android_log_print(ANDROID_LOG_DEBUG, "START", "NULL HERE"); 
    } else {
        __android_log_print(ANDROID_LOG_DEBUG, "START", "ALL FINE"); 
    }

К сожалению, по какой-то неизвестной причине это запись / сброс:

Exception Ljava/lang/NoSuchMethodError; thrown while initializing Lcom/sample/SampleClazz;
NULL HERE

При работе с другими решениями я пытался переместить GetMethodId вметод JNI_OnLoad, чтобы посмотреть, смогу ли я правильно извлечь ссылку на метод из исходного потока Java.Работает нормально ... Но как ни странно, когда я делаю это Код внутри обратного вызова также начинает работать .

Я в полном недоумении.Я понятия не имею, что происходит, и не уверен, что попробовать дальше.

Ответы [ 2 ]

0 голосов
/ 05 февраля 2013

Я знаю, что это было давным-давно, но у меня была такая же проблема.Я обнаружил, что мой класс Java не использовался ни в одном коде Java, поэтому его оптимизировали.Я использовал класс Java в своем приложении, и теперь все это работает со стороны Си.

0 голосов
/ 05 марта 2012

До сих пор я объяснил это ошибкой, возникающей в другом месте, и это является признаком именно такой проблемы. Я создал этот набор методов и теперь использую check() после каждого из моих вызовов:

void check(jclass toCheck) {
    if(toCheck == NULL) {
        __android_log_print(ANDROID_LOG_ERROR, "Check", "Error retrieving jclass");
    }
}

void check(jmethodID toCheck) {
    if(toCheck == NULL) {
        __android_log_print(ANDROID_LOG_ERROR, "Check", "Error retrieving jmethodID");
    }
}

void check(jfieldID toCheck) {
    if(toCheck == NULL) {
        __android_log_print(ANDROID_LOG_ERROR, "Check", "Error retrieving jfieldID");
    }
}

void check(jobject toCheck) {
    if(toCheck == NULL) {
        __android_log_print(ANDROID_LOG_ERROR, "Check", "Error retrieving jobject");
    }
}

Простое добавление этих проверок уже решило мою проблему ... Ради здравомыслия я надеюсь, что есть иная причина, кроме "магии", чтобы объяснить, почему это так ...

Боюсь, хотя мне придется признать, что ранее при выполнении кода возникло странное исключение, и это было просто симптомом более раннего сбоя.

Урок: не забывайте изолировать свой код от людей! Если JNI терпит крах, он сохраняет это при себе, и что-то в будущем сломается вместо этого.

...