Llamar al miembro de la clase JAVA desde el código nativo C / C ++
Estoy escribiendo una aplicación OpenGL C / C ++ que estoy portando a Android a través de Android NDK, JNI apoyo. Tengo dificultades para ejecutar código de devolución de llamada JAVA señalado desde nativo.
Aquí está el código:
- ¿Cómo podemos agregar la imagen animada / simple como una capa superior al video y exportarla como un solo video en Android?
- Error de segmentación en la biblioteca nativa cuando se ejecuta bajo Android antes de 4.0.3
- Newbie en Android NDK: definición en Android.mk
- ¿Las funciones de Android JNI se ejecutan en el hilo principal?
- Android: Uso de JNI desde NativeActivity
class OpenGLSurfaceView extends GLSurfaceView { … public OpenGLSurfaceView(Context context, int deviceWidth, int deviceHeight) { super(context); nativeObj = new NativeLib(); mRenderer = new OpenGLRenderer(context, nativeObj, deviceWidth, deviceHeight); setRenderer(mRenderer); setRenderMode(RENDERMODE_WHEN_DIRTY); } … private void CallBack() { // force redraw requestRender(); } } class OpenGLRenderer implements GLSurfaceView.Renderer { … public void onSurfaceCreated(GL10 gl, EGLConfig config) { nativeObj.init(…); nativeObj.cachejavaobject(JNIEnv *env, jobject obj); // for caching obj on native side } public void onSurfaceChanged(GL10 gl, int w, int h) { } public void onDrawFrame(GL10 gl) { nativeObj.draw(…); } }
Y en código nativo tengo una función texturesLoaded () que se señala cuando algunas texturas se cargan completamente en otro hilo y necesito forzar una actualización de nativeLib.draw (…) en el lado JAVA. Aquí es cómo lo hago:
Caché el JavaVM, jClass, jMethodID en JNI_OnLoad, y gJObjectCached
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) { gJVM = jvm; // cache the JavaVM pointer LogNativeToAndroidExt("JNILOAD!!!!!!!!!!"); JNIEnv *env; int status = gJVM->GetEnv((void **)&env, JNI_VERSION_1_6); if(status < 0) { LogNativeToAndroidExt("Failed to get JNI environment, assuming native thread"); status = gJVM->AttachCurrentThread(&env, NULL); if(status < 0) { LogNativeToAndroidExt("callback_handler: failed to attach current thread"); return JNI_ERR; } } gJClass = env->FindClass("com/android/newlineactivity/NewLineGLSurfaceView"); if(gJClass == NULL) { LogNativeToAndroidExt("Can't find Java class."); return JNI_ERR; } gJMethodID = env->GetMethodID(gJClass, "callback", "()V"); if(gJMethodID == NULL) { LogNativeToAndroidExt("Can't find Java method void callback()"); return JNI_ERR; } return JNI_VERSION_1_6;
}
JNIEXPORT void Java_com_android_OpenGL_NativeLib_cachejavaobject(JNIEnv* env, jobject obj) { // cache the java object gJObjectCached = obj; ... }
Y luego en texturesLoaded () lo hago:
void texturesLoaded() { // Cannot share a JNIEnv between threads. You should share the JavaVM, and use JavaVM->GetEnv to discover the thread's JNIEnv JNIEnv *env = NULL; int status = gJVM->GetEnv((void **)&env, JNI_VERSION_1_6); if(status < 0) { LogNativeToAndroidExt("callback_handler: failed to get JNI environment, assuming native thread"); status = gJVM->AttachCurrentThread(&env, NULL); if(status < 0) { LogNativeToAndroidExt("callback_handler: failed to attach current thread"); return; } } LogNativeToAndroidExt("Calling JAVA method from NATIVE C/C++"); env->CallVoidMethod(gJObjectCached, gJMethodID); LogNativeToAndroidExt("DONE!!!"); }
Resultado … desde el lado nativo obtengo la clase, obtengo el método, el método se llama, pero cuando alcanza / llama a requestRender () dentro (o tratando de acceder a cualquier otro método de miembro de GLSurfaceView se bloquea!)
No puedo intentar con CallStaticVoidMethod (gJClass, gjMethodID); Porque entonces no tengo acceso a requestRender ();
Cualquier idea o opinión, tal vez estoy haciendo algo mal aquí.
Gracias
- Error :() referencia indefinida a `__android_log_write 'ERROR?
- Android NDK: ¿Cómo limpiar el código nativo después de reiniciar la actividad?
- Detección de fugas de memoria nativas en el código JNI de Android
- ¿Qué es "jobject this" en JNI y para qué se utiliza?
- Accede al GPS en Android desde C ++
- JNI operaciones de mapa de bits, para ayudar a evitar OOM cuando se utilizan imágenes grandes
- JNI proguard obfuscation
- El mejor enfoque para cargar múltiples bibliotecas nativas en la aplicación para Android
Debe crear referencias globales a la clase / objeto que almacena. Las referencias que está guardando son referencias locales , que no se pueden compartir entre los subprocesos y desaparecen cuando el tiempo de ejecución limpia la pila de referencia local JNI.
Echa un vistazo a la documentación de Sun / Oracle para referencias globales y locales , y echa un vistazo a los métodos JNIEnv::NewGlobalRef
y JNIEnv::DeleteGlobalRef
.
gJClass = env->NewGlobalRef(env->FindClass( ... )); gJObjectCached = env->NewGlobalRef(obj);
(Editar: resulta que no necesita referencias globales para ID de método.)