La llamada al método nativo dos veces de una biblioteca de terceros en una actividad hace que la aplicación de Android se cierre
He integrado dos bibliotecas nativas (.so) en mi aplicación. Las bibliotecas compilar bien y puedo cargarlos en mi aplicación también. La primera vez que invoco un método nativo de una biblioteca que funciona bien, pero si vuelvo a llamar al mismo método en la actividad de la aplicación se cierra.
El problema al que me enfrento es exactamente el mismo que se menciona aquí:
Http://grokbase.com/t/gg/android-ndk/1226m68ydm/app-exit-on-second-native-call
- Android mupdf libmupdf.so error de ejecución "Ninguna implementación encontrada para openFile nativo"
- ¿Podemos acceder al controlador de micrófono de mi teléfono Android
- Camino de directorio de DCIM en Android - Valor de retorno
- Opencv Android: java.lang.UnsatisfiedLinkError: dlopen falló: no se pudo cargar la librería "libopencv_java.so"
- La aplicación de Android NDK no puede acceder a ningún punto de interrupción
La solución que funciona es invocar el método nativo en otra actividad y cerrarlo con fuerza a través de System.exit (0). Después del artículo intenté fijar los punteros a NULL del método llamado después de una operación acertada, pero esto también no me ayudó. También no es posible descargar una biblioteca una vez cargada por System.loadLibrary ().
Quiero llamar a los métodos nativos más de una vez sin crear una nueva Actividad. ¿Alguna idea de cómo resolver este problema?
(FINALMENTE ENCONTRÉ UNA SOLUCIÓN … AQUÍ ES)
Bueno, finalmente he encontrado una manera de resolver este problema. La solución es bastante simple. Cree otra biblioteca nativa independiente (biblioteca de utilidades) para cargar y descargar las otras bibliotecas. Lo que necesitamos hacer es usar dlopen () y dlclose () en el método nativo de la utilidad. Podemos cargar la biblioteca de utilidades como antes a través de System.loadLibrary ().
Así que en el método nativo de la biblioteca de servicios públicos lo que tenemos que hacer es:
Utilice #include <dlfcn.h>
// Esto es necesario para llamar a las funciones dlopen () y dlclose ().
Proporcione el manipulador y el prototipo de la función:
void *handle; typedef int (*func)(int); // define function prototype func myFunctionName; // some name for the function
Abra la biblioteca a través de dlopen ():
handle = dlopen("/data/data/my.package.com/lib/somelibrary.so", RTLD_LAZY);
Obtener y llamar a la función de la biblioteca:
myFunctionName = (func)dlsym(handle, "actualFunctionNameInLibrary"); myFunctionName(1); // passing parameters if needed in the call
Ahora que la llamada está terminada. Cierre a través de dlclose ():
dlclose(handle);
Espero que esto ayude a otros enfrentando el mismo problema.
- ¿Cómo puedo realizar el procesamiento de eventos sin bloqueo en Android?
- Configuraciones de firma de Android y conflicto con splits abi
- Cómo capturar UnsatisifiedLinkError cuando se utiliza biblioteca NDK-construida en una aplicación para Android?
- ¿Cómo puedo crear una aplicación NDK con Android Studio 2.1 y com.android.tools.build:gradle:2.1.0?
- Cómo utilizar la API de malla experimental con Project Tango
- Aplicación para Android con 2 librerías con jniLibs - bloquea la aplicación
- Llamar a un método java desde c ++ en Android
- Jni llama al método java que toma una interfaz java personalizada como parámetro
Así que … mi solución estaba iniciando un servicio que ejecuta el código de la biblioteca compartida, este servicio tiene un nombre de proceso diferente (se puede configurar en el manifiesto de Android), ya que es un proceso diferente que puede matar (Using Process.killProcess (Process.myPid ()) cuando termine de ejecutarse, sin afectar su aplicación de ninguna manera.
Trabajó muy bien para mí, espero que ayude a alguien más.
Como este es el primer hit para este tema y como el problema aún existe, parece que el enfoque que ZakiMak compartió con nosotros sigue siendo la solución más popular.
Para otros que quieran implementarla y quieran un poco más de detalle para los últimos lanzamientos de Android, he aquí algunas notas que hice al tropezar con esto:
- En primer lugar, hay una solución que implementa este enfoque en GitHub ahora. No lo he probado personalmente, pero lo he utilizado como referencia. Es muy útil ver cómo está estructurado el archivo Android.mk y cómo se abre la biblioteca y se llaman a los métodos. El enlace está aquí: https://github.com/jhotovy/android-ffmpeg
- La ruta a la carpeta de la biblioteca nativa cambia a través de las versiones de Android y también parece cambiar cada vez que ejecuta la aplicación (aunque esto puede ser sólo en modo de depuración). De cualquier manera, lo mejor es pasar la ruta desde el método Java llamante si es posible. Por ejemplo:
En la clase de envolvente de 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); }
En la biblioteca nativa "primera" o "externa":
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); }
- El archivo de Android.mk es un poco escamoso para ponerlo cortésmente. Debido a que está construyendo dos bibliotecas separadas en un archivo de Android.mk, esto puede ser un poco más complejo que otros NDK hacer archivos así que si usted consigue algunos errores extraños hacer una cierta búsqueda antes de que usted comience a tomar su proyecto aparte. Por ejemplo: https://stackoverflow.com/a/6243727/334402
- Cómo jugar gif en android de url?
- Tomar una foto lo más rápido posible con la API de la cámara en Android