Enviar int s entre Java y C

Tengo un código Java de procesamiento de imagen en Android que actúa sobre dos matrices grandes de int. La mayoría de las veces, Java es lo suficientemente rápido, pero necesito usar C a través de JNI y el NDK para acelerar algunas operaciones.

La única manera que sé que puedo pasar los datos de los arrays de int a C es utilizar ByteBuffer.allocateDirect para crear un nuevo búfer, copiar los datos a eso y luego hacer que el código C actúe sobre el búfer.

Sin embargo, no puedo ver ninguna manera que pueda manipular los datos en este búfer en Java como si el búfer fuera un int [] o un byte []. Por ejemplo, una llamada a ByteBuffer.array () fallará en el búfer recién creado. ¿Hay alguna forma de hacer que esto funcione?

Tengo memoria limitada y quiero reducir cuántos arrays / buffers necesito. Por ejemplo, sería bueno que pudiera usar IntBuffer.wrap (new int […]) para crear el búfer y luego manipular la matriz respaldando el búfer directamente en Java pero no puedo hacer esto porque lo único que parece Trabajo aquí para JNI es ByteBuffer.allocateDirect.

¿Hay alguna otra forma de enviar datos entre C y Java? ¿Puedo de alguna manera asignar memoria en el lado C y tener Java enviar datos directamente a allí?

Edit: Una referencia que compara el uso del búfer con int [] usa:

int size = 1000; IntBuffer allocateDirect = java.nio.ByteBuffer.allocateDirect(4 * size).asIntBuffer(); for (int i = 0; i < 100; ++i) { for (int x = 0; x < size; ++x) { int v = allocateDirect.get(x); allocateDirect.put(x, v + 1); } } int[] intArray = new int[size]; for (int i = 0; i < 100; ++i) { for (int x = 0; x < size; ++x) { int v = intArray[x]; intArray[x] = v + 1; } } 

En un teléfono Droid, la versión del búfer lleva ~ 10 segundos para finalizar y la versión del arreglo toma ~ 0.01 segundos.

Desde http://java.sun.com/docs/books/jni/html/objtypes.html , utilice JNI's Get/Release<TYPE>ArrayElements(...)

En este ejemplo, pasaré una matriz (por razones de argumento, es int array = new int[10] y luego llenarlo con 0-9

  JNIEXPORT jint JNICALL Java_IntArray_doStuffArray(JNIEnv *env, jobject obj, jintArray arr) { // initializations, declarations, etc jint *c_array; jint i = 0; // get a pointer to the array c_array = (*env)->GetIntArrayElements(env, arr, NULL); // do some exception checking if (c_array == NULL) { return -1; /* exception occurred */ } // do stuff to the array for (i=0; i<10; i++) { c_array[i] = i; } // release the memory so java can have it again (*env)->ReleaseIntArrayElements(env, arr, c_array, 0); // return something, or not.. it's up to you return 0; } 

Estudio de la sección 3.3, y específicamente 3.3.2 – esto le permitirá obtener un puntero a la matriz en la memoria de java, modificarlo y liberarlo, en efecto que le permite modificar la matriz en código nativo.

Acabo de usarlo en mi propio proyecto (con arreglos cortos) y funciona muy bien 🙂

Si está utilizando buffers asignados directamente, puede acceder a la matriz de respaldo directamente desde C, utilizando la función GetDirectBufferAddress . Esto evita la posibilidad de copiar regiones del área.

Usted puede operar en la dirección devuelta directamente como lo haría con una matriz C normal, y modificará directamente el búfer de Java asignado directamente.

A continuación, como estados ephemient, puede utilizar ByteBuffer.asIntBuffer () y la familia para acceder al búfer de una manera que emula los arreglos de las diversas primitivas Java.

http://download.oracle.com/javase/1.4.2/docs/guide/jni/jni-14.html

Puede utilizar la devolución de llamada para enviar los datos desde la capa nativa a Java.

En capa Java: en mi clase nativa tengo los siguientes métodos:

 //Native method public native String getStrData(int size); //Callback method public void addData(char[] native_data, int size) { ... } 

En capa nativa: en mi implementación nativa:

 JNIEXPORT jstring JNICALL Java_com_pkg_NativeClass_getStrData (JNIEnv *env, jobject obj, jint size) { ... jclass native_class; /* Callback: native class */ jmethodID native_method_id; /* Callback: native method id */ jcharArray row; /* Callback: native data */ ... /* Start Callback: Native to Java */ native_class = (*env)->GetObjectClass(env, obj); native_method_id = (*env)->GetMethodID(env, native_class, "addData", "([CI)V"); if (native_method_id == 0) { return (jstring)ERR_NATIVE_METHODID; } row = (jcharArray)(*env)->NewCharArray(env, size); /* jc has the data to be sent to Java */ (*env)->SetCharArrayRegion(env, (jcharArray)row, (jsize)0, size, (jchar *)jc); (*env)->CallVoidMethod(env, obj, native_method_id, row, size); /* End Callback */ ... } 
  • Compilar Java para Android nativo en lugar de escribir en C
  • Cómo capturar excepciones generadas con código nativo que se ejecuta en Android
  • Macro de preprocesador en Android.mk se ignora, pero funciona en Application.mk
  • Uso de bibliotecas pre-construidas y jni en Android Studio
  • Suma de dos valores usando ndk android
  • JNI- java.lang.UnsatisfiedLinkError: Método nativo no encontrado
  • Error de libcurl CURLE_SSL_CACERT_BADFILE en android
  • Biblioteca no encontrada debido a targetSdkVersion (armeabi-v7a y libcryptopp.so)
  • No se puede iniciar cygpath en android
  • Leer el campo entero del objeto Java con C ++ (JNI)
  • ¿Cómo puedo capturar SIGSEGV (error de segmentación) y obtener un seguimiento de pila bajo JNI en Android?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.