Вызов собственного метода дважды из сторонней библиотеки в Activity приводит к закрытию приложения Android

Я включил в свое приложение две родные библиотеки (.so). Библиотеки компилируются отлично, и я могу загрузить их и в приложение. В первый раз, когда я вызываю собственный метод библиотеки, он отлично работает, но если я снова вызову тот же метод в Activity, приложение отключится.

Проблема, с которой я столкнулась, точно такая же, как упоминалось здесь:
http://grokbase.com/t/gg/android-ndk/1226m68ydm/app-exit-on-second-native-call

Решение, которое работает, – это вызвать собственный метод в другом действии и принудительно закрыть его с помощью System.exit (0). После статьи я попытался установить указатели на NULL вызываемого метода после успешной операции, но это тоже не помогло мне. Также невозможно выгрузить библиотеку после ее загрузки System.loadLibrary ().

Я хочу вызывать собственные методы более одного раза, не создавая новое действие. Есть идеи, как решить эту проблему?

(Я НАКОНЕЦ НАДЕЕТСЯ РЕШЕНИЕ … ЗДЕСЬ ЭТО)

Хорошо, я наконец нашел способ решить эту проблему. Решение на самом деле довольно простое. Создайте другую независимую библиотеку (утилиту) для загрузки и выгрузки других библиотек. Нам нужно использовать dlopen () и dlclose () в собственном методе утилиты. Мы можем загрузить библиотеку утилиты, как раньше, через System.loadLibrary ().

Поэтому в собственном методе библиотеки утилиты нам нужно:

Используйте #include <dlfcn.h> // это необходимо для вызова функций dlopen () и dlclose ().

Предоставить прототип обработчика и функции:

 void *handle; typedef int (*func)(int); // define function prototype func myFunctionName; // some name for the function 

Откройте библиотеку через dlopen ():

 handle = dlopen("/data/data/my.package.com/lib/somelibrary.so", RTLD_LAZY); 

Получить и вызвать функцию библиотеки:

 myFunctionName = (func)dlsym(handle, "actualFunctionNameInLibrary"); myFunctionName(1); // passing parameters if needed in the call 

Теперь, когда вызов завершен. Закройте его через dlclose ():

 dlclose(handle); 

Надеюсь, это поможет другим, столкнувшимся с одной и той же проблемой.

Итак … мое решение запускало сервис, который запускает код общей библиотеки, у этой службы есть другое имя процесса (вы можете установить его в манифесте Android), так как это другой процесс, который вы можете его убить (используя Process.killProcess (Process.myPid ()) при завершении работы без какого-либо влияния на ваше приложение.

Работал очень хорошо для меня, надеюсь, что это помогает кому-то другому.

Поскольку это самый популярный продукт для этой проблемы, и поскольку сама проблема по-прежнему существует, кажется, что подход, который ZakiMak поделил с нами, по-прежнему остается самым популярным решением.

Для других, которые могут захотеть реализовать его и хотели бы получить более подробную информацию о последних выпусках Android, вот некоторые заметки, которые я сделал, когда я наткнулся на это:

  • Во-первых, есть решение, которое реализует этот подход на GitHub сейчас. Я не пробовал это лично, но я использовал его как ссылку. Очень полезно посмотреть, как структурирован файл Android.mk и как открывается библиотека, а также методы. Ссылка находится здесь: https://github.com/jhotovy/android-ffmpeg
  • Путь к папке с родной библиотекой изменяется по версиям Android, и он также меняется каждый раз при запуске приложения (хотя это может быть только в режиме отладки). В любом случае лучше всего пройти путь от вызывающего Java-метода, если это возможно. Например:

В классе оболочки Java:

 import android.content.Context; import android.util.Log; public class FfmpegJNIWrapper { //This class provides a Java wrapper around the exposed JNI ffmpeg functions. static { //Load the 'first' or 'outer' JNI library so this activity can use it System.loadLibrary("ffmpeg_wraper_multi_invoke_jni"); } public static int call_ffmpegWrapper(Context appContext, String[] ffmpegArgs) { //Get the native libary path String nativeLibPath = appContext.getApplicationInfo().nativeLibraryDir; //Call the method in the first or 'outer' library, passing it the //native library past as well as the original args return ffmpegWrapper(nativeLibPath, ffmpegArgs); } // Native methods for ffmpeg functions public static native int ffmpegWrapper(String nativeLibPath, String[] argv); } 

В «первой» или «внешней» исходной библиотеке:

 JNIEXPORT jint JNICALL Java_com_yourpackage_androidffmpegwrapper_FfmpegJNIWrapper_ffmpegWrapper(JNIEnv *pEnv, jobject pObj, jstring nativeLibPath, jobjectArray javaArgv) { //Get the second or 'inner' native library path char* nativePathPassedIn = (char *)(*pEnv)->GetStringUTFChars(pEnv, nativeLibPath, NULL); char ourNativeLibraryPath[256]; snprintf(ourNativeLibraryPath, sizeof (ourNativeLibraryPath), "%s%s", nativePathPassedIn, "/libffmpeg_wraper_jni.so"); //the name of your ffmpeg library //Open the so library void *handle; typedef int (*func)(JNIEnv*, jobject, jobjectArray); handle = dlopen(ourNativeLibraryPath, RTLD_LAZY); if (handle == NULL) { __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "could not open library: %s", dlerror()); printf("Could not dlopen(\"libbar.so\"): %s\n", dlerror()); return(-1); } //Call the ffmpeg wrapper functon in the second or 'inner' library func reenterable_ffmpegWrapperFunction; reenterable_ffmpegWrapperFunction = (func)dlsym(handle, "Java_com_yourpackage_androidffmpegwrapper_FfmpegJNIWrapper_ffmpegWrapper"); reenterable_ffmpegWrapperFunction(pEnv, pObj, javaArgv); //the original arguments //Close the library dlclose(handle); // return return(1); } 
  • Файл Android.mk немного «сломанный», чтобы выразить это вежливо. Поскольку вы создаете две отдельные библиотеки в одном файле Android.mk, это может быть немного сложнее, чем другие NDK делать файлы, поэтому, если вы получите некоторые странные ошибки, выполните некоторые поиски, прежде чем вы начнете разделять ваш проект. Например: https://stackoverflow.com/a/6243727/334402
Intereting Posts
Как создать падающий снег в AndEngine? Изменение угла Android StackView Что произойдет с не обновленными приложениями, которые выполняют код, который требует разрешения, которое пользователь разрешил в Android 6.0 Marshmallow Импорт нескольких проектов и отдельных проектов в Android Studio Android Cast v3: не удается найти какое-либо устройство Странное поведение `drawTextOnPath ()` с аппаратным ускорением Android: FATAL EXCEPTION: FinalizerWatchdogDaemon Как показать фиксированное количество элементов строк в recyclerview RecyclerView: выделение выбранного элемента Почему Android Studio всегда показывает ActionBar в дизайне приложения, даже когда он отключен? Изменение системной даты Android-телефона при нажатии кнопки с помощью приложения android ActionBar скрывается при появлении клавиатуры Первый кадр фонового видео не отображается на Android Поддержание как бесплатных, так и сторонних версий приложения Res 'не существует в Eclipse