Làm cách nào để trả về một mảng từ JNI sang Java?


130

Tôi đang cố gắng sử dụng NDK của Android.

Có cách nào để trả về một mảng (trong trường hợp của tôi là int[]) được tạo trong JNI cho Java không? Nếu vậy, vui lòng cung cấp một ví dụ nhanh về chức năng JNI sẽ thực hiện việc này.

-Cảm ơn

Câu trả lời:


120

Nếu bạn đã kiểm tra tài liệu mà vẫn có câu hỏi nên là một phần của câu hỏi ban đầu của bạn. Trong trường hợp này, hàm JNI trong ví dụ tạo ra một số mảng. Mảng bên ngoài bao gồm một mảng 'Đối tượng' được tạo bằng hàm JNI NewObjectArray(). Từ quan điểm của JNI, đó là tất cả một mảng hai chiều, một mảng đối tượng có chứa một số mảng bên trong khác.

Vòng lặp for sau đây tạo ra các mảng bên trong có kiểu int [] bằng cách sử dụng hàm JNI NewIntArray(). Nếu bạn chỉ muốn trả về một mảng ints một chiều, thì NewIntArray()hàm là thứ bạn sử dụng để tạo giá trị trả về. Nếu bạn muốn tạo một chuỗi Chuỗi một chiều thì bạn sẽ sử dụng NewObjectArray()hàm nhưng với một tham số khác cho lớp.

Vì bạn muốn trả về một mảng int, nên mã của bạn sẽ trông giống như thế này:

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

Vâng, tôi đã làm điều đó rồi. Tôi đã gặp khó khăn trong việc hiểu ví dụ liên quan đến vấn đề của tôi (cái cuối cùng) và tôi đã tự hỏi liệu ai đó có thể giải thích một ví dụ đơn giản hơn chỉ bằng cách trả về một int [].
RyanCheu

EDIT: Hãy bỏ qua nhận xét trước đây của tôi, đoạn mã trên không hoạt động. Cảm ơn bạn! Điều đó rất hữu ích.
RyanCheu

3
EDIT2: Mã hoạt động, nhưng bạn phải thay đổi tmp trong SetIntArrayRegion (...) để điền.
RyanCheu

41

nếu ai đó muốn biết cách trả về mảng String []:

mã java

private native String[] data();

xuất khẩu bản địa

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

mã nguồn

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

từ liên kết: http://www.coderanch.com/t/326467/java/java/Return-String-array-program-Java


0

Dựa trên câu hỏi được hỏi, điều này đã được giải thích trong câu trả lời đầu tiên rằng làm thế nào chúng ta có thể vượt qua int [] thông qua jobjectArray. Nhưng đây là một ví dụ về cách chúng ta có thể trả về một jobjectArray chứa danh sách dữ liệu. Điều này có thể hữu ích cho các tình huống, ví dụ: khi ai đó cần trả về dữ liệu ở định dạng 2D để vẽ một số dòng có điểm x và y. Ví dụ dưới đây cho thấy cách jobjectArray có thể trả về dữ liệu dưới dạng định dạng sau:

Đầu vào Java vào JNI:
Array [ Arraylistcủa x float points] [Arraylist của y float points]

JNI xuất ra java:
jobjectArray[ Arraylistof x float points] [ Arraylistof y float points]

    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

Giải pháp đơn giản là ghi dữ liệu mảng vào một tệp từ C và sau đó truy cập tệp từ Java

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.