私は、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[]
、次に、
- JNIの使用
NewIntArray()
を返す関数、jintArray
指定した長さを。それから - 最終的には(下記参照)の要素を設定するための適切なJNIメソッドを使用し、
- いずれかで、対象オブジェクトのフィールドに直接配列を割り当てる
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);