Come restituire un array da JNI a Java?


130

Sto tentando di utilizzare Android NDK.

C'è un modo per restituire un array (nel mio caso un int[]) creato in JNI a Java? In tal caso, fornire un rapido esempio della funzione JNI che lo farebbe.

-Grazie

Risposte:


120

Se hai esaminato la documentazione e hai ancora domande che dovrebbero far parte della domanda iniziale. In questo caso, la funzione JNI nell'esempio crea un numero di matrici. L'array esterno è costituito da un array "Object" creato con la funzione JNI NewObjectArray(). Dal punto di vista di JNI, questo è tutto un array bidimensionale, un array di oggetti contenente un numero di altri array interni.

Il seguente ciclo per crea le matrici interne che sono di tipo int [] usando la funzione JNI NewIntArray(). Se desideri solo restituire un array monodimensionale di ints, la NewIntArray()funzione è quella che utilizzeresti per creare il valore restituito. Se si desidera creare un array monodimensionale di stringhe, utilizzare la NewObjectArray()funzione ma con un parametro diverso per la classe.

Poiché vuoi restituire un array int, il tuo codice sarà simile a questo:

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;
}

Sì, l'ho già fatto. Avevo difficoltà a comprendere l'esempio correlato al mio problema (l'ultimo) e mi chiedevo se a qualcuno sarebbe dispiaciuto spiegare un esempio più semplice semplicemente restituendo un int [].
RyanCheu,

EDIT: Per favore ignora il mio commento precedente, il codice sopra funziona. Grazie! È stato molto utile.
RyanCheu,

3
EDIT2: il codice funziona, ma è necessario modificare tmp in SetIntArrayRegion (...) per riempire.
RyanCheu,

41

se qualcuno desidera sapere come restituire l'array String []:

codice java

private native String[] data();

esportazione nativa

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

Codice 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);  
  }  

dal link: http://www.coderanch.com/t/326467/java/java/Returning-String-array-program-Java


0

Sulla base della domanda posta, questo è già spiegato nella prima risposta che come possiamo passare int [] tramite jobjectArray. Ma ecco un esempio di come possiamo restituire un jobjectArray che contiene elenchi di dati. Questo può essere utile ad esempio in situazioni: quando qualcuno deve restituire dati in formato 2D per disegnare una linea con punti xey. L'esempio seguente mostra come un jobjectArray può restituire dati sotto forma del seguente formato:

Input Java per JNI:
Array [ Arraylistof x float points] [ Arraylistof y float points]

Output JNI su java:
jobjectArray[ Arraylistdi x punti float] [ Arraylistdi y punti float]

    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;

-6

La soluzione semplice è quella di scrivere i dati dell'array in un file da C, quindi accedere al file da Java

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.