我的C/C++语言学习进阶之旅JNI开发之Java传递实体Bean到C++层,实体Bean包含intfloat等基本类型和数组arrayList集合等
Posted 字节卷动
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我的C/C++语言学习进阶之旅JNI开发之Java传递实体Bean到C++层,实体Bean包含intfloat等基本类型和数组arrayList集合等相关的知识,希望对你有一定的参考价值。
一、需求描述
最近有个需求,Java上层包装一系列的数据到一个实体bean,实体Bean包含int、float等基本类型和数组array、List集合等,然后通过JNI传递给C++层来进行数据处理,这边折腾了一番终于搞定,这里记录一下。
1.1 Java实体bean
首先,Java层实体bean代码如下:
package com.oyp.ndkdemo;
import android.graphics.PointF;
import java.util.List;
public class FaceFeatureBean
public int faceId;
public PointF[] boundingBox;
public PointF[] landmarks;
public List<Float> visibilities;
public float yaw;
public float pitch;
public float roll;
public FaceFeatureBean(int faceId, PointF[] boundingBox, PointF[] landmarks, List<Float> visibilities, float yaw, float pitch, float roll)
this.faceId = faceId;
this.boundingBox = boundingBox;
this.landmarks = landmarks;
this.visibilities = visibilities;
this.yaw = yaw;
this.pitch = pitch;
this.roll = roll;
public int getFaceId()
return faceId;
public void setFaceId(int faceId)
this.faceId = faceId;
public PointF[] getBoundingBox()
return boundingBox;
public void setBoundingBox(PointF[] boundingBox)
this.boundingBox = boundingBox;
public PointF[] getLandmarks()
return landmarks;
public void setLandmarks(PointF[] landmarks)
this.landmarks = landmarks;
public List<Float> getVisibilities()
return visibilities;
public void setVisibilities(List<Float> visibilities)
this.visibilities = visibilities;
public float getYaw()
return yaw;
public void setYaw(float yaw)
this.yaw = yaw;
public float getPitch()
return pitch;
public void setPitch(float pitch)
this.pitch = pitch;
public float getRoll()
return roll;
public void setRoll(float roll)
this.roll = roll;
1.2 Java实体bean转成Kotlin实体bean
当然,上面的Java实体bean也可以转成Kotlin实体bean,代码简洁一些,如下所示:
package com.oyp.ndkdemo
import android.graphics.PointF
class FaceFeatureBean(
var faceId: Int,
var boundingBox: Array<PointF>,
var landmarks: Array<PointF>,
var visibilities: List<Float>,
var yaw: Float,
var pitch: Float,
var roll: Float
)
二、JNI实现相关
2.1 编写Native方法入口
编写Native方法入口,如下所示:
// Kotlin对外public的方法,用于业务调用
fun setFaceFeature(feature: FaceFeatureBean)
nativeSetFaceFeatureBean(feature)
// Native层方法
private external fun nativeSetFaceFeatureBean(feature: FaceFeatureBean)
// Kotlin对外public的方法,用于业务调用
fun setFaceFeature2(feature: FaceFeatureBean)
nativeSetFaceFeatureBean2(feature)
// Native层方法
private external fun nativeSetFaceFeatureBean2(feature: FaceFeatureBean)
2.2 实现Native方法
这个方法的套路基本上是:
- 通过
env->GetObjectClass
拿到jclass - 通过
env->GetMethodID
拿到jmethodID - 通过
env->CallIntMethod
拿到属性 - 通过
env->GetArrayLength
拿到数组的长度,将拿到的就jobject
对象转换为数组的指针jobjectArray *
,然后遍历数组 - 拿到
List
集合之后,通过调用List
的相关方法拿到List
的size
和get
方法,然后遍历List
集合
代码如下:
extern "C"
JNIEXPORT void JNICALL
Java_com_oyp_ndkdemo_JNI_nativeSetFaceFeatureBean(JNIEnv *env, jobject thiz, jobject feature)
LOGD("=================================Java_com_oyp_ndkdemo_JNI_nativeSetFaceFeatureBean=================================")
// 获取FaceFeatureBean类
jclass jFeature = env->GetObjectClass(feature);
// 获取FaceFeatureBean对象的methodID
jmethodID getFaceId = env->GetMethodID(jFeature, "getFaceId", "()I");
jmethodID getYaw = env->GetMethodID(jFeature, "getYaw", "()F");
jmethodID getPitch = env->GetMethodID(jFeature, "getPitch", "()F");
jmethodID getRoll = env->GetMethodID(jFeature, "getRoll", "()F");
// 执行方法 拿到属性
jint faceId = env->CallIntMethod(feature, getFaceId);
jfloat yaw = env->CallFloatMethod(feature, getYaw);
jfloat pitch = env->CallFloatMethod(feature, getPitch);
jfloat roll = env->CallFloatMethod(feature, getRoll);
LOGD("faceId = %d,yaw = %f,pitch = %f,roll = %f", faceId, yaw, pitch, roll)
jmethodID getVisibilities = env->GetMethodID(jFeature, "getVisibilities", "()Ljava/util/List;");
jobject visibilities = env->CallObjectMethod(feature, getVisibilities);
// 遍历 visibilities,拿到List的各个Item
// 获取ArrayList对象
jclass jcs_alist = env->GetObjectClass(visibilities);
// 获取ArrayList的methodid
jmethodID alist_get = env->GetMethodID(jcs_alist, "get", "(I)Ljava/lang/Object;");
jmethodID alist_size = env->GetMethodID(jcs_alist, "size", "()I");
jint len = env->CallIntMethod(visibilities, alist_size);
for (int i = 0; i < len; i++)
// 获取 Float 对象
jobject float_obj = env->CallObjectMethod(visibilities, alist_get, i);
// 获取 Float 类
jclass float_cls = env->GetObjectClass(float_obj);
jmethodID getFloatValue = env->GetMethodID(float_cls, "floatValue", "()F");
jfloat floatValue = env->CallFloatMethod(float_obj, getFloatValue);
LOGD("visibilities列表中 第 %d 个值为:floatValue = %f", i + 1, floatValue)
jmethodID getBoundingBox = env->GetMethodID(jFeature, "getBoundingBox",
"()[Landroid/graphics/PointF;");
jobject boundingBox = env->CallObjectMethod(feature,getBoundingBox);
auto * boundingBoxArray = reinterpret_cast<jobjectArray *>(&boundingBox);
const jint length = env->GetArrayLength(*boundingBoxArray);
for(int i=0;i<length;i++)
jobject point= env->GetObjectArrayElement(*boundingBoxArray,i);
//1.获得实例对应的class类
jclass jcls = env->GetObjectClass(point);
//2.通过class类找到对应的field id
//num 为java类中变量名,I 为变量的类型int
jfieldID xID = env->GetFieldID(jcls,"x","F");
jfieldID yID = env->GetFieldID(jcls,"y","F");
jfloat x = env->GetFloatField(point,xID);
jfloat y = env->GetFloatField(point,yID);
LOGD("boundingBoxArray数组中 第 %d 个值为:x = %f , y = %f", i + 1, x,y)
jmethodID getLandmarks = env->GetMethodID(jFeature, "getLandmarks",
"()[Landroid/graphics/PointF;");
jobject landmarks = env->CallObjectMethod(feature,getLandmarks);
auto * landmarksArray = reinterpret_cast<jobjectArray *>(&landmarks);
const jint length2 = env->GetArrayLength(*landmarksArray);
for(int i=0;i<length2;i++)
jobject point= env->GetObjectArrayElement(*landmarksArray,i);
//1.获得实例对应的class类
jclass jcls = env->GetObjectClass(point);
//2.通过class类找到对应的field id
//num 为java类中变量名,I 为变量的类型int
jfieldID xID = env->GetFieldID(jcls,"x","F");
jfieldID yID = env->GetFieldID(jcls,"y","F");
jfloat x = env->GetFloatField(point,xID);
jfloat y = env->GetFloatField(point,yID);
LOGD("landmarksArray 第 %d 个值为:x = %f , y = %f", i + 1, x,y)
如上所示,我们分了如下几个步骤来实现:
2.2.1. 获取FaceFeatureBean类
// 获取FaceFeatureBean类
jclass jFeature = env->GetObjectClass(feature);
2.2.2. 获取FaceFeatureBean对象的methodID
// 获取FaceFeatureBean对象的methodID
jmethodID getFaceId = env->GetMethodID(jFeature, "getFaceId", "()I");
jmethodID getYaw = env->GetMethodID(jFeature, "getYaw", "()F");
jmethodID getPitch = env->GetMethodID(jFeature, "getPitch", "()F");
jmethodID getRoll = env->GetMethodID(jFeature, "getRoll", "()F");
2.2.3. 执行方法,拿到属性
// 执行方法 拿到属性
jint faceId = env->CallIntMethod(feature, getFaceId);
jfloat yaw = env->CallFloatMethod(feature, getYaw);
jfloat pitch = env->CallFloatMethod(feature, getPitch);
jfloat roll = env->CallFloatMethod(feature, getRoll);
LOGD("faceId = %d,yaw = %f,pitch = %f,roll = %f", faceId, yaw, pitch, roll)
我们查看代码可知,实际上就是执行我标记的几个方法:getFaceId、getYaw、getPitch、getRoll
2.2.4. 解析List集合
首先执行getVisibilities
方法,拿到集合对象
jmethodID getVisibilities = env->GetMethodID(jFeature, "getVisibilities", "()Ljava/util/List;");
jobject visibilities = env->CallObjectMethod(feature, getVisibilities);
然后通过List对象,拿到get方法的methodID和size方法的methodID,执行size方法拿到List集合长度。
// 遍历 visibilities,拿到List的各个Item
// 获取ArrayList对象
jclass jcs_alist = env->GetObjectClass(visibilities);
// 获取ArrayList的methodid
jmethodID alist_get = env->GetMethodID(jcs_alist, "get", "(I)Ljava/lang/Object;");
jmethodID alist_size = env->GetMethodID(jcs_alist, "size", "()I");
jint len = env->CallIntMethod(visibilities, alist_size);
get和size方法对应的java层代码如下
这样我们拿到了集合长度以及获取到了get方法methodID,那么就可以遍历集合了,完整如下所示:
// 遍历 visibilities,拿到List的各个Item
// 获取ArrayList对象
jclass jcs_alist = env->GetObjectClass(visibilities);
// 获取ArrayList的methodid
jmethodID alist_get = env->GetMethodID(jcs_alist, "get", "(I)Ljava/lang/Object;");
jmethodID alist_size = env->GetMethodID(jcs_alist, "size", "()I");
jint len = env->CallIntMethod(visibilities, alist_size);
for (int i = 0; i < len; i++)
// 获取Float对象
jobject float_obj = env->CallObjectMethod(visibilities, alist_get, i);
// 获取 Float类
jclass float_cls = env->GetObjectClass(float_obj);
jmethodID getFloatValue = env->GetMethodID(float_cls, "floatValue", "()F");
jfloat floatValue = env->CallFloatMethod(float_obj, getFloatValue);
LOGD("visibilities列表中 第 %d 个值为:floatValue = %f", i + 1, floatValue)
因为我们遍历的是List<Float>
,所以拿到的每一个Item对象都是Float,接着我们要解析Float,拿到它的值,这时候,我们需要执行floatValue
方法拿到它的值。
下面是执行floatValue
方法,拿到值,接着打印的代码
// 获取Float对象
jobject float_obj = env->CallObjectMethod(visibilities, alist_get, i);
// 获取 Float类
jclass float_cls = env->GetObjectClass(float_obj);
jmethodID getFloatValue = env->GetMethodID(float_cls, "floatValue", "()F");
jfloat floatValue = env->CallFloatMethod(float_obj, getFloatValue);
LOGD("visibilities列表中 第 %d 个值为:floatValue = %f", i + 1, floatValue)
2.2.5. 解析对象数组
jmethodID getBoundingBox = env->GetMethodID(jFeature, "getBoundingBox",
"()[Landroid/graphics/PointF;");
jobject boundingBox = env->CallObjectMethod(feature,getBoundingBox);
auto * boundingBoxArray = reinterpret_cast<jobjectArray *>(&boundingBox);
const jint length = env->GetArrayLength(*boundingBoxArray);
for(int i=0;i<length;i++)
jobject point= env->GetObjectArrayElement(*boundingBoxArray,i);
//1.获得实例对应的class类
jclass jcls = env->GetObjectClass(point);
//2.通过class类找到对应的field id
//num 为java类中变量名,I 为变量的类型int
jfieldID xID = env->GetFieldID(jcls,"x","F");
jfieldID yID = env->GetFieldID(jcls,"y","F");
jfloat x = env->GetFloatField(point,xID);
jfloat y = env->GetFloatField(point,yID);
LOGD("boundingBoxArray数组中 第 %d 个值为:x = %f , y = %f", i + 1, x,y)
- 首先我们通过
getBoundingBox
方法,拿到了数组对象。
jmethodID getBoundingBox = env->GetMethodID(jFeature, "getBoundingBox",
"()[Landroid/graphics/PointF;");
jobject boundingBox = env->CallObjectMethod(feature,getBoundingBox);
- 但是这个是
jobject
,而不是jobjectArray
,因此我们需要强转一下,让它变成jobjectArray *
指针
auto * boundingBoxArray = reinterpret_cast<jobjectArray *>(&boundingBox);
- 接着我们拿到数组的长度
const jint length = env->GetArrayLength(*boundingBoxArray);
- 拿到了数组指针和数组长度,那我们就可以遍历了,如下所示:
for(int i=0;i<length;i++)
jobject point= env->GetObjectArrayElement(*boundingBoxArray,i);
//1.获得实例对应的class类
jclass jcls = env->GetObjectClass(point);
//2.通过class类找到对应的field id
//num 为java类中变量名,I 为变量的类型int
jfieldID xID = env->GetFieldID(jcls,"x","F");
jfieldID yID = env->GetFieldID(jcls,"y","F");
jfloat x = env->GetFloatField我的C/C++语言学习进阶之旅JNI开发之转换C层返回的结构体为Java实体Bean
我的C/C++语言学习进阶之旅JNI开发之Java传递实体Bean到C++层,实体Bean包含intfloat等基本类型和数组arrayList集合等
我的C/C++语言学习进阶之旅JNI开发之Java传递实体Bean到C++层,实体Bean包含intfloat等基本类型和数组arrayList集合等
我的C/C++语言学习进阶之旅转载:实现一个在JNI中调用Java对象的工具类