gpt4 book ai didi

java - 无法从 JNI 设置 Java int 数组字段

转载 作者:太空狗 更新时间:2023-10-29 20:19:40 28 4
gpt4 key购买 nike

我正在开发一个 Android 应用程序,我正在从 C++ 库中接收相机数据。我需要将此数据从 C++ 发送到 Java 代码。为此,我正在使用 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);

...没问题,前提是该字段已经包含对长度至少为 16int[] 的引用。由于它对您不起作用,我认为该字段的初始值不满足该标准。

如果您需要创建一个新的 Java int[],那么

  1. 使用 JNI 的 NewIntArray() 函数,它返回一个具有您指定长度的 jintArray。然后
  2. 使用适当的 JNI 方法设置元素(见下文),最后
  3. 使用 SetObjectField() 将数组直接分配给目标对象的字段,或者使用对象的 setter 方法来执行此操作,就像您的第一次尝试一样。

至于设置 Java 数组的元素,SetIntArrayRegion() 可以很好地工作(给定一个足够长的实际 Java 数组),但这确实需要您分配一个单独的 native 数组从中复制值的基元(您的 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);

关于java - 无法从 JNI 设置 Java int 数组字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57309382/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com