¿Cómo devolver una matriz de JNI a Java?

130

Estoy intentando usar el NDK de Android.

¿Hay alguna manera de devolver una matriz (en mi caso una int[]) creada en JNI a Java? Si es así, proporcione un ejemplo rápido de la función JNI que haría esto.

-Gracias

RyanCheu
fuente

Respuestas:

120

Si ha examinado la documentación y todavía tiene preguntas que deberían ser parte de su pregunta inicial. En este caso, la función JNI en el ejemplo crea una serie de matrices. La matriz externa se compone de una matriz 'Object' que se crea con la función JNI NewObjectArray(). Desde la perspectiva de JNI, eso es todo una matriz bidimensional, una matriz de objetos que contiene una serie de otras matrices internas.

El siguiente bucle for crea las matrices internas que son de tipo int [] utilizando la función JNI NewIntArray(). Si solo quisiera devolver una matriz dimensional única de entradas, entonces la NewIntArray()función es la que usaría para crear el valor de retorno. Si quisiera crear una matriz tridimensional única de cadenas, utilizaría la NewObjectArray()función pero con un parámetro diferente para la clase.

Como desea devolver una matriz int, su código se verá así:

JNIEXPORT jintArray JNICALL Java_ArrayTest_initIntArray(JNIEnv *env, jclass cls, int size)
{
 jintArray result;
 result = (*env)->NewIntArray(env, size);
 if (result == NULL) {
     return NULL; /* out of memory error thrown */
 }
 int i;
 // fill a temp structure to use to populate the java int array
 jint fill[size];
 for (i = 0; i < size; i++) {
     fill[i] = 0; // put whatever logic you want to populate the values here.
 }
 // move from the temp structure to the java structure
 (*env)->SetIntArrayRegion(env, result, 0, size, fill);
 return result;
}
Jherico
fuente
Sí, eso ya lo hice. Estaba teniendo problemas para entender el ejemplo relacionado con mi problema (el último), y me preguntaba si a alguien le importaría explicar un ejemplo más simple con solo devolver un int [].
RyanCheu
EDITAR: ignore mi comentario anterior, el código anterior funciona. ¡Gracias! Eso fue muy útil.
RyanCheu
3
EDIT2: El código funciona, pero debe cambiar tmp en SetIntArrayRegion (...) para completar.
RyanCheu
41

si alguien quisiera saber cómo devolver la matriz String []:

código java

private native String[] data();

exportación nativa

JNIEXPORT jobjectArray JNICALL Java_example_data() (JNIEnv *, jobject);

código nativo

  JNIEXPORT jobjectArray JNICALL   
               Java_example_data  
  (JNIEnv *env, jobject jobj){  

    jobjectArray ret;  
    int i;  

    char *message[5]= {"first",   
                       "second",   
                       "third",   
                       "fourth",   
                       "fifth"};  

    ret= (jobjectArray)env->NewObjectArray(5,  
         env->FindClass("java/lang/String"),  
         env->NewStringUTF(""));  

    for(i=0;i<5;i++) {  
        env->SetObjectArrayElement(  
        ret,i,env->NewStringUTF(message[i]));  
    }  
    return(ret);  
  }  

desde el enlace: http://www.coderanch.com/t/326467/java/java/Returning-String-array-program-Java

zajac.m2
fuente
0

Según la pregunta formulada, esto ya se explica en la primera respuesta de cómo podemos pasar int [] a través de jobjectArray. Pero aquí hay un ejemplo de cómo podemos devolver un jobjectArray que contiene listas de datos. Esto puede ser útil para situaciones, por ejemplo: cuando alguien necesita devolver datos en formato 2D para dibujar alguna línea con puntos x e y. El siguiente ejemplo muestra cómo un jobjectArray puede devolver datos en el siguiente formato:

Entrada de Java al JNI:
matriz [ Arraylistde x puntos flotantes] [ Arraylistde puntos flotantes y]

Salida JNI a Java:
jobjectArray[ Arraylistde x puntos flotantes] [ Arraylistde y puntos flotantes]

    extern "C" JNIEXPORT jobjectArray JNICALL
        _MainActivity_callOpenCVFn(
                JNIEnv *env, jobject /* this */,
                jobjectArray list) {

         //Finding arrayList class and float class(2 lists , one x and another is y)
            static jclass arrayListCls = static_cast<jclass>(env->NewGlobalRef(env->FindClass("java/util/ArrayList")));
            jclass floatCls = env->FindClass("java/lang/Float");
         //env initialization of list object and float
            static jmethodID listConstructor = env->GetMethodID(arrayListCls, "<init>", "(I)V");
            jmethodID alGetId  = env->GetMethodID(arrayListCls, "get", "(I)Ljava/lang/Object;");
            jmethodID alSizeId = env->GetMethodID(arrayListCls, "size", "()I");
            static jmethodID addElementToList = env->GetMethodID(arrayListCls, "add", "(Ljava/lang/Object;)Z");

            jmethodID floatConstructor = env->GetMethodID( floatCls, "<init>", "(F)V");
            jmethodID floatId = env->GetMethodID(floatCls,"floatValue", "()F");


        //null check(if null then return)
        if (arrayListCls == nullptr || floatCls == nullptr) {
            return 0;
        }

    //     Get the value of each Float list object in the array
        jsize length = env->GetArrayLength(list);

        //If empty
        if (length < 1) {
            env->DeleteLocalRef(arrayListCls);
            env->DeleteLocalRef(floatCls);
            return 0;
        }

// Creating an output jObjectArray
    jobjectArray outJNIArray = env->NewObjectArray(length, arrayListCls, 0);

        //taking list of X and Y points object at the time of return
        jobject  xPoint,yPoint,xReturnObject,yReturnObject;

            //getting the xList,yList object from the array
            jobject xObjFloatList = env->GetObjectArrayElement(list, 0);
            jobject yObjFloatList = env->GetObjectArrayElement(list, 1);


     // number of elements present in the array object
        int xPointCounts = static_cast<int>(env->CallIntMethod(xObjFloatList, alSizeId));

        static jfloat xReturn, yReturn;
                jobject xReturnArrayList = env->NewObject(arrayListCls,listConstructor,0);
        jobject yReturnArrayList = env->NewObject(arrayListCls,listConstructor,0);

    for (int j = 0; j < xPointCounts; j++) {
            //Getting the x points from the x object list in the array
            xPoint = env->CallObjectMethod(xObjFloatList, alGetId, j);
            //Getting the y points from the y object list in the array
            yPoint = env->CallObjectMethod(yObjFloatList, alGetId, j);

//Returning jobjectArray(Here I am returning the same x and points I am receiving from java side, just to show how to make the returning `jobjectArray`)  

            //float x and y values
            xReturn =static_cast<jfloat >(env->CallFloatMethod(xPoint, floatId,j));
            yReturn =static_cast<jfloat >(env->CallFloatMethod(yPoint, floatId,j));


            xReturnObject = env->NewObject(floatCls,floatConstructor,xReturn);
             yReturnObject = env->NewObject(floatCls,floatConstructor,yReturn);

            env->CallBooleanMethod(xReturnArrayList,addElementToList,xReturnObject);


            env->CallBooleanMethod(yReturnArrayList,addElementToList,yReturnObject);
            env->SetObjectArrayElement(outJNIArray,0,xReturnArrayList);
            env->SetObjectArrayElement(outJNIArray,1,yReturnArrayList);
        __android_log_print(ANDROID_LOG_ERROR, "List of X and Y are saved in the array","%d", 3);

    }

    return outJNIArray;
Paramita
fuente
-6

La solución simple es escribir los datos de la matriz en un archivo desde C y luego acceder al archivo desde Java

Jeyanth
fuente