2012-05-18 2 views
12

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

Проблема я столкнулся точно так же, как указано здесь:
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); 

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

+0

где вы делаете dlclose (handle)? Я имею в виду в коде Activity или JNI? –

+0

Его в коде JNI. Это функция, доступная через заголовочный файл dlfcn.h. – ZakiMak

+0

ok получил, я вижу, что вы загружаете и выгружаете другие библиотеки в этом классе c. Но как мне привязать его к моему Java-коду? –

ответ

5

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

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

+0

Я думаю, что это чистое решение. Это труднее, но лучше. – ezefire

2

Поскольку это вершина хит для этой проблемы, и поскольку сама проблема все еще существует, кажется, что подход, который 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
Смежные вопросы