No se puede establecer campo de matriz int Java desde JNI

sitivic:

Estoy desarrollando una aplicación para Android y estoy recibiendo datos de la cámara de un lib en C ++. Necesito enviar estos datos de C ++ para el código Java. Por esto, yo estoy usando JNI. Soy capaz de establecer diferentes campos en Java desde el los datos de C ++ (como el nombre o el tipo de la cámara) y JNI, pero soy incapaz de establecer el campo ID porque es una uint8_tmatriz.

¿Cómo puedo hacer esto?

Ya he intentado varias maneras de hacer esto, pero cada vez que tengo una SIGSEGV errorcon una dirección no válida. Para otros campos que estoy usando

env->Set<Primitives>Field(jobject, jfieldID, value)

método, pero no existen métodos como que para intarray, hay? Por lo tanto, he tratado de establecer este campo llamando a un método de mi clase y proporcionar la intmatriz como parámetro pero esta función de error y devolvió el SIGSEGV error.

Entonces, busqué en la web y he tratado de establecer el campo a través

env->GetObjectField(jobject, jfieldID)

y

env->SetIntArrayRegion(jintArray, start, end, myIntArray)

pero aquí el primer método devuelve siempre nula.

JavaVM * mJVM; //My Java Virtual Machine
jobject mCameraObject, mThreadObject; //Previously initialize to call functions in the right thread

void onReceiveCameraList(void *ptr, uint32_t /*id*/, my::lib::Camera *arrayCamera, uint32_t nbCameras) {

    JNIEnv *env;
    mJVM->AttachCurrentThread(&env, nullptr);
    if (env->ExceptionCheck())
        return;

    //Get Field, Method ID, Object and Class
    jclass cameraClass = env->GetObjectClass(mCameraObject);

    jfieldID camIDField = env->GetFieldID(cameraClass, "idCam", "[I");
    jfieldID camNameField = env->GetFieldID(cameraClass, "label", "Ljava/lang/String;");
    jfieldID camConnectedField = env->GetFieldID(cameraClass, "connected", "Z");
    jfieldID camTypeField = env->GetFieldID(cameraClass, "typeProduit", "B");

    jmethodID camReceptionMID = env->GetMethodID(env->GetObjectClass(mThreadObject), "onCamerasReception", "([Lcom/my/path/models/Camera;)V"); //Java function
    jobjectArray cameraArray = env->NewObjectArray(nbCameras, cameraClass, mCameraObject); //Object return in the functions

    //Put the cameras into the vector
    std::vector<my::lib::Camera> vectorCameras;
    if(!vectorCameras.empty())
        vectorCameras.clear();

    if ((arrayCamera != nullptr) && (nbCameras > 0)) {
        for (uint32_t i = 0; i < nbCameras; ++i) {
            vectorCameras.push_back(arrayCamera[i]);
        }
    }

    //Set the my::lib::Camera field into Java::Camera
    int c= 0;
    for (auto & cam : vectorCameras)
    {
        jobject camera = env->AllocObject(cameraClass); //Object Camera to add in cameraArray object

    // MY DATA TO SET ID FIELD ///
    jint idArray[16];
        for (int i = 0; i < 16 ; ++i) {
            idArray[i] = cam.idCamera.data[i]; // uint8_t cam.idCamera.data[16]
        }

    ///////// FIRST WAY  /////////
    jmethodID setIDCamMID = env->GetMethodID(env->GetObjectClass(camera), "setIDCam", "([I)V");
    env->CallVoidMethod(camera, setIDCamMID, idArray);

    ///////// SECOND WAY /////////
        jintArray jintArray1 = (jintArray)env->GetObjectField(camera, camIDField);
        env->SetIntArrayRegion(jintArray1, 0, 16, idArray);

    //Set<Primitives>Field : WORKING
        env->SetObjectField(camera, camNameField, env->NewStringUTF((const char *) cam.labelCamera));
        env->SetBooleanField(camera, camConnectedField, cam.isCameraConnected);
        jbyte type;
        if (cam.typeCamera == my::lib::TYPE_1 || cam.typeCamera == my::lib::TYPE_2 || cam.typeCamera == my::lib::TYPE_3) //type not known in JAVA
            type = 0;
        else
            type = cam.typeCamera;
        env->SetByteField(camera, camTypeField, type);

    //Put camera object into cameraArray object
        env->SetObjectArrayElement(cameraArray, c++, camera);
    }//for

    //Call Java method with cameraArray
    env->CallVoidMethod(mThreadObject, camReceptionMID, dpCameraArray);

}//onreceiveCamera

Alguien me puede decir si he cometido un error o estoy usando el camino equivocado?
¿Hay alguna otra manera de establecer estos datos?

John Bollinger:

Esto produce una C ++ array con elementos de tipo jint:

    // MY DATA TO SET ID FIELD ///
    jint idArray[16];
        for (int i = 0; i < 16 ; ++i) {
            idArray[i] = cam.idCamera.data[i]; // uint8_t cam.idCamera.data[16]
        }

Es importante entender que esto no es un Java matriz . Por lo tanto, este ...

    ///////// FIRST WAY  /////////
    jmethodID setIDCamMID = env->GetMethodID(env->GetObjectClass(camera), "setIDCam", "([I)V");
    env->CallVoidMethod(camera, setIDCamMID, idArray);

... Es incorrecto. idArrayNo es el tipo correcto (y no decae a un puntero al tipo correcto) para el parámetro correspondiente al método Java que está intentando invocar.

Por otro lado, este ...

    ///////// SECOND WAY /////////
        jintArray jintArray1 = (jintArray)env->GetObjectField(camera, camIDField);
        env->SetIntArrayRegion(jintArray1, 0, 16, idArray);

... está bien, siempre y cuando el campo ya contiene una referencia a una int[]de la longitud de al menos 16 . Dado que no funcionó en su caso, puedo considerar que el valor inicial del campo no satisface dicho criterio.

Si necesita crear un nuevo Javaint[] , a continuación,

  1. utilizar JNI de NewIntArray()función, que devuelve una jintArraycon la longitud que se especifique. Luego
  2. utilizar los métodos JNI adecuadas para establecer los elementos (ver más abajo), y finalmente
  3. o bien asignar la matriz directamente al campo del objeto de destino con SetObjectField()o utilizar un método seleccionador del objeto para hacerlo, ya que en su primer intento.

En cuanto a la configuración de los elementos de la matriz de Java, SetIntArrayRegion()no tendrán ningún problema para que (dada una matriz real de Java de longitud suficiente), pero eso se requieren para asignar una matriz nativa separada de primitivas (su idArray) de la que copiar los valores. Un enfoque ligeramente más eficiente sería utilizar GetPrimitiveArrayCritical()para dejar de Java proporciona el buffer - posiblemente un puntero directo a los datos internos - y luego ReleasePrimitiveArrayCritical()cuando haya terminado. Algo como esto:

// It is assumed here that the length of the array is sufficient, perhaps because
// we just created this (Java) array.
jint *idArray = (jint *) env->GetPrimitiveArrayCritical(jintArray1, NULL);

for (uint32_t i = 0; i < nbCameras; ++i) {
    idArray[i] = cam.idCamera.data[i];
}
env->ReleasePrimitiveArrayCritical(jintArray1, idArray, 0);

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=229808&siteId=1
Recomendado
Clasificación