JNIからJavaのint配列フィールドを設定することができません。

sitivic:

私は、Androidアプリケーションを開発していると私はC ++内のlibからカメラデータを受信しています。私は、JavaコードにC ++からこのデータを送信する必要があります。このために、私は、JNIを使用しています。私は、JNIと(名前やカメラの種類など)C ++のデータから、Javaで異なるフィールドを設定することができるよ、私はそれがありますので、IDフィールドを設定することができませんでしだuint8_t配列。

これどうやってするの?

私はすでにこれを行うには、いくつかの方法を試してみましたが、それぞれの時間は、私が持っているSIGSEGV error、無効なアドレスで。私が使用している他のフィールドについて

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

この方法が、ためにそのようには方法がないint配列は、がありますか?だから、私は私のクラスからメソッドを呼び出すことで、このフィールドを設定して提供しようとしたintパラメータとして配列をしかし、この関数は失敗し、返されましたSIGSEGV error

その後、私は、ウェブ上で検索し、私はを通じてフィールドを設定しようとしました

env->GetObjectField(jobject, jfieldID)

そして

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

しかし、ここで第一の方法は、常にnullを返します。

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

私はミスを犯した場合、誰かが私に言うことができるか、それを間違った方法を使用していますか?
このデータを設定するための他の方法はありますか?

ジョン・ボリンジャー:

これは、タイプの要素を持つC ++の配列を生成します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]
        }

ことを理解することが重要であることではないのJava配列したがって、この...

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

... 間違っている。idArrayあなたが起動しようとしているJavaのメソッドに対応するパラメータのために(と右型へのポインタに減衰しない)右タイプではありません。

一方、この...

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

...、OKであるフィールドが既にへの参照含まれていることを提供int[]長さの少なくとも16それはあなたのために動作しませんでしたので、私は、フィールドの初期値は、その基準を満たしていないことをそれを取ります。

あなたが作成する必要がある場合は、新規のJavaをint[]、次に、

  1. JNIの使用NewIntArray()を返す関数、jintArray指定した長さを。それから
  2. 最終的には(下記参照)の要素を設定するための適切なJNIメソッドを使用し、
  3. いずれかで、対象オブジェクトのフィールドに直接配列を割り当てるSetObjectField()か、あなたの最初の試みのように、そうするように、オブジェクトのセッターメソッドを使用します。

Java配列の要素を設定するためとして、SetIntArrayRegion()(十分な長さの実際のJava配列を指定して)そのための罰金に動作しますが、それはプリミティブ(あなたの別々のネイティブ配列を割り当てるためにあなたを必要としないidArray)、そこから値をコピーします。もう少し効率的なアプローチを用いることであろうGetPrimitiveArrayCritical()当時と-おそらく内部データへの直接のポインタを- Javaはバッファを提供できるようにするReleasePrimitiveArrayCritical()設定が完了したとき。このようなもの:

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

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=229805&siteId=1