2016-10-07 2 views
2

Я бы хотел использовать библиотеку dlib для обнаружения лиц, но она не работает на старых телефонах.GetFieldID не работает на Android 4.4 и старше

I падает со следующей трассировки стека:

E/AndroidRuntime(4288): FATAL EXCEPTION: pool-1-thread-1 
E/AndroidRuntime(4288): java.lang.ExceptionInInitializerError 
E/AndroidRuntime(4288): at com.tzutalin.dlibtest.MainActivity.runDetectAsync(MainActivity.java:235) 
E/AndroidRuntime(4288): at com.tzutalin.dlibtest.MainActivity_.access$301(MainActivity_.java:34) 
E/AndroidRuntime(4288): at com.tzutalin.dlibtest.MainActivity_$6.execute(MainActivity_.java:158) 
E/AndroidRuntime(4288): at org.androidannotations.api.BackgroundExecutor$Task.run(BackgroundExecutor.java:405) 
E/AndroidRuntime(4288): at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:442) 
E/AndroidRuntime(4288): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) 
E/AndroidRuntime(4288): at java.util.concurrent.FutureTask.run(FutureTask.java:137) 
E/AndroidRuntime(4288): at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:150) 
E/AndroidRuntime(4288): at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:264) 
E/AndroidRuntime(4288): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076) 
E/AndroidRuntime(4288): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569) 
E/AndroidRuntime(4288): at java.lang.Thread.run(Thread.java:856) 
E/AndroidRuntime(4288): Caused by: java.lang.NoSuchFieldError: no field with name='mLabel' signature='java/lang/String' in class Lcom/tzutalin/dlib/VisionDetRet; 
E/AndroidRuntime(4288): at com.tzutalin.dlib.PeopleDet.jniNativeClassInit(Native Method) 
E/AndroidRuntime(4288): at com.tzutalin.dlib.PeopleDet.<clinit>(PeopleDet.java:42) 
E/AndroidRuntime(4288): ... 12 more 

Таким образом, код C выглядит следующим образом:

void JNIEXPORT DLIB_JNI_METHOD(jniNativeClassInit)(JNIEnv* env, jclass _this) { 
    jclass detRetClass = env->FindClass("com/tzutalin/dlib/VisionDetRet"); 
    CHECK_NOTNULL(detRetClass); 
    gVisionDetRetOffsets.label = 
     env->GetFieldID(detRetClass, "mLabel", "java/lang/String"); 
    gVisionDetRetOffsets.confidence = 
     env->GetFieldID(detRetClass, "mConfidence", "F"); 
    gVisionDetRetOffsets.left = env->GetFieldID(detRetClass, "mLeft", "I"); 
    gVisionDetRetOffsets.top = env->GetFieldID(detRetClass, "mTop", "I"); 
    gVisionDetRetOffsets.right = env->GetFieldID(detRetClass, "mRight", "I"); 
    gVisionDetRetOffsets.bottom = env->GetFieldID(detRetClass, "mBottom", "I"); 
    gVisionDetRetOffsets.addLandmark = 
     env->GetMethodID(detRetClass, "addLandmark", "(II)Z"); 
    if (gVisionDetRetOffsets.addLandmark == NULL) { 
    LOG(FATAL) << "Can't Find Method addLandmark(int,int)"; 
    } 
    LOG(INFO) << "JniNativeClassIni Success"; 
} 

и связанный с этим Java класс:

public final class VisionDetRet { 
    private String mLabel; 
    private float mConfidence; 
    private int mLeft; 
    private int mTop; 
    private int mRight; 
    private int mBottom; 
    private ArrayList<Point> mLandmarkPoints = new ArrayList<>(); 

    VisionDetRet() { 
    } 

    // Other code 
} 

Итак, поля, очевидно, здесь, и он получает класс (CHECK_NOTNULL(detRetClass) успешно). Так почему же он падает на старые телефоны? Google не очень помог, и я довольно новичок в материалах NDK/JNI.

PS Java-файл here и файл С here (да, они находятся в 2-х разных РЕПО)

+1

Подсказка: Используйте что-то вроде этого, когда требуются подписи JNI-стиль: 'javap -s -classpath yourBinDirectory com.tzutalin. dlib.VisionDetRef | grep -A 2 "mLabel" '(Если у вас нет grep, вы должны быть в Windows. Используйте [Gow] (https://github.com/bmatzelle/gow/wiki) Если у вас нет Gow , получите его с помощью [chocolatey] (https://chocolatey.org/).) –

ответ

3

Я не знаю, как это работает для вас на любом Android версии, потому что java/lang/String является неправильная подпись для GetFieldID.

Для классов, подпись должна быть L fully-qualified-class ;, так что в вашем случае, вы хотите Ljava/lang/String;