无法从JNI设置Java Int数组字段
Unable to set Java int array field from JNI
我正在开发一个Android应用程序,并且正在从C 中的LIB接收相机数据。我需要将这些数据从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)
但是这里第一个方法返回始终为空。
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 array 。因此,这个...
///////// 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);
...没关系,提供该字段已经包含对长度至少16 的int[]
的引用。由于它对您不起作用,所以我认为该字段的初始值不满足该标准。
如果您需要创建 new 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);
对于第一种方法,您需要首先创建一个Java int[]
,从idArray
填写,然后然后 调用您的方法:
jintArray j_arr = env->NewIntArray(16);
env->SetIntArrayRegion(j_arr, 0, 16, idArray);
env->CallVoidMethod(camera, setIDCamMID, j_arr);
您的第二种方法不起作用,因为您从未调用填充idCam
字段的构造函数。但是,您可以从JNI做到这一点,但是:
env->SetObjectField(camera, camIDField, j_arr);
- 按字符值访问int数组
- 将 int 数组转换为 std::vector<int*>
- C++,在int数组中输入字符串或字符会输出0,而不是ascii或error
- 整数区间(或 int 数组)中每个数字的出现次数
- Int 数组到C++容器
- C++ 未初始化的本地(非全局)int 数组中的元素类型到底是什么?
- 如何检测将文本文件读入 int 数组的新行
- C++快速将 int 数组内容转储到文本文件中
- <string> 如何在使用 SWIG 时将 int 数组和 List 作为参数传递给 C# C++
- 如何制作不允许重复值的 C++ int 数组循环?
- 如何将逗号分隔的文件读取为 2D int 数组?
- int 数组,但索引是字符?
- 使用可变参数函数将整数和/或整数数组放入单个 int 数组中
- 将 int 数组转换为带有小数C++的双精度数组
- 将双精度值分配给 int 数组时的类型转换
- 已编辑 我如何将其拆分为 char 和 int 数组
- 从 C++ 中的 int ** 数组访问元素
- C++程序无法分配 int 数组?
- 我正在编写一个代码来将 int 数组存储在文件中,然后用 c++ 检索它,但是检索第一项是假值,我该如何解决这个问题?
- 如何通过头文件中的函数初始化 const int 数组?