在Activity中调用两次第三方库的本机方法会导致Android应用程序closures

我已经在我的应用程序中集成了两个本地库(.so)。 库编译得很好,我也可以在我的应用程序中加载它们。 我第一次调用库的本地方法,它工作正常,但如果我再次在Activity中调用相同的方法,应用程序closures。

我面临的问题与此处提到的完全相同:
http://grokbase.com/t/gg/android-ndk/1226m68ydm/app-exit-on-second-native-call

解决scheme的作用是在另一个Activity中调用本地方法,并通过System.exit(0)强制closures它。 下面的文章我试图设置成功的操作后调用方法的NULL指针,但这也没有帮助我。 一旦它被System.loadLibrary()加载,它也不可能卸载一个库。

我想多次调用本地方法而不创build一个新的活动。 任何想法如何解决这个问题?

(我最终find了一个解决scheme…在这里)

好的,我终于find了解决这个问题的方法。 解决scheme其实很简单。 构build另一个独立的本地库(实用程序库)来加载和卸载其他库。 我们需要做的是在实用程序的本地方法中使用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); 

获取并调用库的function:

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

现在通话完成了。 通过dlclose()closures它:

 dlclose(handle); 

希望这会帮助其他人面临同样的问题。

所以…我的解决scheme是启动一个运行共享库代码的服务,这个服务有一个不同的进程名(你可以在Android Manifest中设置它),因为这是一个不同的进程,你可以杀死它(使用Process.killProcess (Process.myPid())完成运行时,不会以任何方式影响您的应用程序。

为我工作得很好,希望能帮助别人。

由于这是这个问题的头等大事,而且问题本身依然存在,所以ZakiMak与我们分享的方法似乎仍然是最受欢迎的解决scheme。

对于其他人可能想要实现它,并希望对最新的Android版本稍微详细一点,这里有一些笔记,当我偶然通过这个:

  • 首先,现在有一个在GitHub上实现这个方法的解决scheme。 我个人没有尝试过,但是我用它作为参考。 了解Android.mk文件的结构以及如何打开库和调用方法是非常有用的。 链接在这里: https : //github.com/jhotovy/android-ffmpeg
  • 原生库文件夹的path改变了Android版本,并且每次运行应用程序时都会改变(尽pipe这可能只是在debugging模式下)。 无论哪种方式,如果可能,最好从调用Java方法中传递path。 例如:

在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文件中build立两个独立的库,所以这可能会更复杂一点,因为如果你有一些奇怪的错误,在开始拆分你的项目之前先做一些search。 例如: https : //stackoverflow.com/a/6243727/334402