usar nativos metodos java c jni android-ndk

nativos - ¿Cómo pasar estructuras C de ida y vuelta al código Java en JNI?



metodos nativos en java (4)

Tengo algunas funciones C a las que llamo a través de JNI que toman un puntero a una estructura, y algunas otras funciones que asignan / liberan un puntero al mismo tipo de estructura para que sea un poco más fácil tratar con mi envoltorio . Sorprendentemente, la documentación de JNI dice muy poco sobre cómo lidiar con las estructuras de C.

Mi archivo de encabezado C se ve así:

typedef struct _MyStruct { float member; } MyStruct; MyStruct* createNewMyStruct(); void processData(int *data, int numObjects, MyStruct *arguments);

El archivo JNI C wrapper correspondiente contiene:

JNIEXPORT jobject JNICALL Java_com_myorg_MyJavaClass_createNewMyStruct(JNIEnv *env, jobject this) { return createNewMyStruct(); } JNIEXPORT void JNICALL Java_com_myorg_MyJavaClass_processData(JNIEnv *env, jobject this, jintArray data, jint numObjects, jobject arguments) { int *actualData = (*env)->GetIntArrayElements(env, data, NULL); processData(actualData, numObjects, arguments); (*env)->ReleaseIntArrayElements(env, data, actualData, NULL); }

... y finalmente, la clase correspondiente de Java:

public class MyJavaClass { static { System.loadLibrary("MyJniLibrary"); } private native MyStruct createNewMyStruct(); private native void processData(int[] data, int numObjects, MyStruct arguments); private class MyStruct { float member; } public void test() { MyStruct foo = createNewMyStruct(); foo.member = 3.14159f; int[] testData = new int[10]; processData(testData, 10, foo); } }

Desafortunadamente, este código bloquea la JVM justo después de createNewMyStruct() . Soy un poco nuevo para JNI y no tengo idea de cuál podría ser el problema.

Editar : Debo señalar que el código C es muy vainilla C, está bien probado y fue portado desde un proyecto de iPhone en funcionamiento. Además, este proyecto utiliza el marco Android NDK, que le permite ejecutar código C nativo desde un proyecto de Android desde JNI. Sin embargo, no creo que esto sea estrictamente un problema de NDK ... parece un error de configuración / inicialización de JNI por mi parte.


  1. Realice la clase tanto en Java como en C ++, solo agregue las variables miembro. Las estructuras de C ++ son realmente solo clases con miembros de datos públicos. Si realmente estás en C pura, deja de leer ahora.
  2. Use su (s) IDE (s) para hacer setters y getters para las variables miembro automáticamente.
  3. Use javah para generar el archivo de encabezado C de la clase Java.
  4. Haga algo de edición en el lado de C ++ para hacer que los setters y getters coincidan con el archivo de encabezado generado.
  5. Ponga el código JNI.

Esta no es una solución ideal, pero puede ahorrarle un poco de tiempo, y al menos le dará un esqueleto que puede editar. Esta funcionalidad se podría agregar a un IDE, pero sin una gran demanda, probablemente no suceda. La mayoría de los IDE ni siquiera admiten proyectos de idiomas mixtos, y mucho menos hacerlos hablar entre ellos.


La estructura C es la colección de variables (algunas son puntero a la función). Pasar a Java no es una buena idea. En general, es el problema de cómo pasar el tipo más complejo a Java, como el puntero.

En el libro de JNI, se recomienda mantener el puntero / estructura en nativo y exportar la manipulación a java. Puedes leer algunos artículos útiles. La Guía y la Especificación del Programador de Interfaz Nativa JavaTM, he leído. 9.5 Las clases pares tienen una solución para manejarlo.


Necesita crear una clase Java con los mismos miembros que C struct, y ''mapearlos'' en el código C a través de los métodos env-> GetIntField, env-> SetIntField, env-> GetFloatField, env-> SetFloatField, y así sucesivamente - en resumen, mucho trabajo manual, ojalá ya existan programas que lo hagan automáticamente: JNAerator ( http://code.google.com/p/jnaerator ) y SWIG ( http://www.swig.org/ ). Ambos tienen sus pros y sus contras, la elección depende de usted.


Se está bloqueando porque Java_com_myorg_MyJavaClass_createNewMyStruct se declara para devolver "jobject", pero en realidad está devolviendo struct MyStruct. Si ejecutó esto con CheckJNI habilitado, la máquina virtual se quejaría en voz alta y abortaría. Su función processData () también va a estar bastante molesta por lo que se entrega en "argumentos".

Un jobject es un objeto en el montón administrado. Puede tener elementos adicionales antes o después de los campos declarados, y los campos no tienen que estar dispuestos en la memoria en ningún orden en particular. Entonces no puedes mapear una estructura C encima de una clase Java.

La forma más directa de tratar con esto se identificó en una respuesta anterior: manipular el proyecto con funciones JNI. Asigne los objetos desde Java o con NewObject, obtenga / establezca los campos del objeto con las llamadas apropiadas.

Hay varias formas de "hacer trampa" aquí. Por ejemplo, podría incluir un byte [] en su objeto Java que contenga sizeof (struct MyStruct) bytes y luego use GetByteArrayElements para obtener un puntero al mismo. Un poco feo, especialmente si también quieres acceder a los campos desde Java.