如何修改字节数组并通过JNI从C++向Java传输?附函数代码
修改字节数组并通过JNI从C++传递到Java的实现指南
先把你给出的代码片段整理成可读性更强的格式:
void FrameReceived(int width, int height, const char *rawImageBytes, int size, jboolean remote) { if(size == 0) return; jboolean isAttached; JNIEnv *env; jint jParticipant; jint jWidth; jint jHeight; jbyte *jRawImageBytes; jbyte *modifiedRawImageBytes; jbyteArray Array; env = getJniEnv(&isAttached); if (env == NULL) goto FAIL0; //LOGE(".... **** ....TRYING TO FIND CALLBACK"); if(remote) { if(frameReceivedRemoteMethod == NULL) frameReceivedRemoteMethod = getApplicationJni... // 代码未完整展示,后续逻辑补充如下 } // 这里是核心逻辑实现区 FAIL0: // 资源清理逻辑 }
接下来我给你补充完整修改字节数组并传递到Java的关键步骤,都是实际项目里常用的写法:
1. 创建Java字节数组并准备修改
首先要把C++里的原始字节数据转换成Java能识别的jbyteArray,同时拿到可修改的原生指针:
// 跳过前面的环境检查,直接写核心逻辑 jbyteArray jImageArray = env->NewByteArray(size); if (jImageArray == nullptr) { LOGE("Failed to create jbyteArray"); goto FAIL0; } // 获取可读写的原生字节指针,第二个参数是是否拷贝(传nullptr让JNI自动处理) jbyte* nativeBuffer = env->GetByteArrayElements(jImageArray, nullptr); if (nativeBuffer == nullptr) { LOGE("Failed to get native buffer from jbyteArray"); env->DeleteLocalRef(jImageArray); goto FAIL0; }
2. 执行字节数组的修改操作
现在你可以直接操作nativeBuffer指针来修改数据,比如做图像像素处理、字节反转、加密等,这里给个示例:
// 示例1:直接拷贝原始数据后修改部分内容 memcpy(nativeBuffer, rawImageBytes, size); // 比如把所有偶数索引的字节置0 for (int i = 0; i < size; i += 2) { nativeBuffer[i] = 0; } // 示例2:直接对原始字节做转换后写入 for (int i = 0; i < size; i++) { // 比如做像素值反转(适合灰度图) nativeBuffer[i] = static_cast<jbyte>(0xFF - static_cast<unsigned char>(rawImageBytes[i])); }
3. 提交修改并调用Java方法传递数组
修改完成后要释放指针并提交修改,然后调用你获取到的Java回调方法:
// 提交修改并释放指针,第三个参数传0表示提交修改并释放内存 env->ReleaseByteArrayElements(jImageArray, nativeBuffer, 0); // 调用Java端的回调方法,假设你的方法签名是void onRemoteFrameReceived(int, int, byte[]) if (frameReceivedRemoteMethod != nullptr) { env->CallVoidMethod(applicationObj, frameReceivedRemoteMethod, width, height, jImageArray); // 检查JNI调用是否抛出异常 if (env->ExceptionCheck()) { env->ExceptionClear(); LOGE("Failed to call Java frame received method"); } } // 记得释放局部引用,避免JNI局部引用表溢出 env->DeleteLocalRef(jImageArray);
4. 完善资源清理逻辑
在FAIL0标签处要处理线程分离和资源释放:
FAIL0: // 如果是动态附加的线程,要分离 if (isAttached == JNI_TRUE && gvm != nullptr) { gvm->DetachCurrentThread(); }
几个关键注意事项
- 局部引用管理:JNI中创建的
jbyteArray、jobject等都是局部引用,必须用DeleteLocalRef释放,否则会导致内存泄漏。 - 线程安全:
JNIEnv是线程专属的,绝对不能跨线程传递,所以每次都要通过getJniEnv获取当前线程的环境。 - 异常检查:每次调用JNI方法后最好检查是否有异常,及时清理避免影响后续逻辑。
内容的提问来源于stack exchange,提问作者rosu alin
相关产品推荐
相关产品推荐

