【问题标题】:How to return an array from JNI to Java?如何将数组从 JNI 返回到 Java?
【发布时间】:2010-12-09 06:20:37
【问题描述】:

我正在尝试使用 android NDK。

有没有办法将在 JNI 中创建的数组(在我的例子中为 int[])返回给 Java?如果是这样,请提供一个可以执行此操作的 JNI 函数的快速示例。

-谢谢

【问题讨论】:

    标签: java android arrays java-native-interface


    【解决方案1】:

    如果您检查了文档,但仍有一些问题应该是您最初问题的一部分。在这种情况下,示例中的 JNI 函数创建了许多数组。外部数组由使用 JNI 函数NewObjectArray() 创建的“对象”数组组成。从 JNI 的角度来看,这就是一个二维数组,一个包含许多其他内部数组的对象数组。

    下面的 for 循环使用 JNI 函数 NewIntArray() 创建 int[] 类型的内部数组。如果您只想返回一个一维整数数组,那么NewIntArray() 函数就是您用来创建返回值的函数。如果您想创建一维字符串数组,那么您将使用 NewObjectArray() 函数,但该类使用不同的参数。

    由于您想返回一个 int 数组,那么您的代码将如下所示:

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

    【讨论】:

    • 是的,我已经这样做了。我无法理解与我的问题相关的示例(最后一个),我想知道是否有人会介意只返回一个 int[] 来解释一个更简单的示例。
    • 编辑:请忽略我之前的评论,上面的代码确实有效。谢谢!这很有帮助。
    • EDIT2:代码有效,但您必须更改 SetIntArrayRegion(...) 中的 tmp 才能填充。
    • 当您超出范围时,您不会得到 NPE - 因为 fill 已被破坏。还是SetIntArrayRegion 会立即复制数据?
    • 根据 JNI 文档,SetIntArrayRegion 和所有类似的原始数组填充函数将数据复制 到 JNI 托管结构中。 fill 数组只需要在函数执行期间有效。
    【解决方案2】:

    如果有人想知道如何返回 String[] 数组:

    java代码

    private native String[] data();
    

    本机导出

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

    本机代码

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

    来自链接: http://www.coderanch.com/t/326467/java/java/Returning-String-array-program-Java

    【讨论】:

      【解决方案3】:

      简单的解决方案是用C将数组数据写入一个文件,然后用Java访问该文件

      【讨论】:

      • 很好的解决方案!
      【解决方案4】:

      根据提出的问题,这已经在第一个答案中解释过,我们如何通过 jobjectArray 传递 int[]。但这是一个示例,我们如何返回包含数据列表的 jobjectArray。这对于以下情况很有帮助:当有人需要以 2D 格式返回数据以绘制带有 x 和 y 点的线时。下面的例子展示了一个 jobjectArray 如何以下列格式返回数据:

      JNI 的 Java 输入:
      数组[Arraylist of x 个浮点数][Arraylist of y 个浮点数]

      JNI 输出到 java:
      jobjectArray[Arraylist of x 个浮点数] [Arraylist of y 个浮点数]

          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;
      

      【讨论】:

        猜你喜欢
        • 2012-01-11
        • 1970-01-01
        • 1970-01-01
        • 2019-11-28
        • 1970-01-01
        • 2017-08-30
        • 2011-09-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多