上篇文章讲述了JNI中C++简单的调用Java函数,接下来我们要解决上次留下的疑惑问题进行解答,如何调用带有结构体的java函数。
假设:C++要给Java传入一个叫做DataSt的结构体,那么,Android也需要定义同样的结构体,保持与so文件中的结构体名称以及字段保持一致,否则查询不到。
结构体内容如下:
struct DataSt{ std::string id; std::vector<int> vetIndex;}
C++传入的数据保存在:std::veC++tor m_vetArray中,在java中是如何接收带有STL的结构体数据呢?
接下来我会逐步进行讲解~
调用讲解
1:定义Java结构体
为了让java代码中获取到C++调用的数据时,此时JAVA中需要定义这样一个DataSt的结构体。
查询JAVA中定义结构体的位置
jclass objClass = mJni->FindClass("cn/test/model/java2so/event/DataSt");
注意此时FindClass对应的就是Java中定义结构体的程序路径,一定要写全,否则无法查询到!
2:创建一个java数组对象
与C++方法一样,想要把数据存储到容器中,需要定义一个这样的容器,这里需要明确容器的大小,也就是需要传给JAVA数据的大小,类似于C++的数组。
int nsize = 10; //假设,需要给java传入10组结构体数据,这里根据实际情况自行定义//创建:数组对象jobjectArray arrayData = mJni->NewObjectArray(nsize, objClass, NULL);if(arrayData == nullptr){ //此时,说明new出来的数组无效 return;}
3:设置JAVA方法
结构中存在了两种变量类型:string、int
获取id方法ID
jmethodID method_id = mJni->GetMethodID(objClass, "setId", "(Ljava/lang/String;)V");
获取vetIndex中一条int值的方法ID
jmethodID method_index = mJni->GetMethodID(objClass, "setIndex", "(I)V");
如果这里不知道如何获取方法,可以结合java结构体自动生成的函数一一对应。
4:类型转换
想要让Java识别C++的数据,我们就需要对类型进行转换,依据DataSt中的两种结构类型进行处理转换
4.1:string -> jstring
假设:string id = "123";
jstring jname = mJni->NewStringUTF(str.c_str());
4.2:int类型
注意:在jni中,int类型是直接可以赋值的,不需要特殊处理
5:遍历方式存储成java结构
这里到了我们存储的重点了,上面的内容都是为这一步做的铺垫。
在第二步骤时,我们假设了C++容器的大小为10,那么,我们这里依旧用10做处理
int nsize = 10;
我们在进行数据存储是,是按照顺序的方式存储,首先我们要定义一个下标方法。
jmethodID method_init_Event = mJni->GetMethodID(objClass, "<init>", "()V");
在进行数据存储时,需要用到这个method_init_Event参数的
在C++中插入一条数据时,例如vector直接push_back方法就可以了,或者也可以使用insert方法。
下面,先将存储的大体框架展示出来
for (int i = 0; i < nsize; i++){ DataSt stInfo = m_vetArray[i]; //C++结构体中的一条数据 //1:创建一个对象用于存储一条数据 jobject objmodel = mJni->NewObject(objClass, method_init_Event, ""); //2:赋值操作 //2.1:将id数据设置到objmodel对象中 //2.2:将vetIndex数据设置到objmodel对象中 //3:将数据设置到Java的Arrary中 mJni->SetObjectArrayElement(arrayData, i, objmodel); }
以上就是粗略的赋值流程了,针对于2操作,我们进行具体的代码展示吧!
操作2.1:将id数据设置到objmodel对象中
第一步:string转成jstring类型
jstring jsId = mJni->NewStringUTF(stInfo.id.c_str());
第二步:存储到objmodel对象中
mJni->CallVoidMethod(objmodel, method_id, jname);
操作2.2:将vetIndex数据设置到objmodel对象中
jclass objClass = mJni->FindClass("cn/test/model/java2so/event/DataSt");0
6:C++调用Java函数传递参数
第五步骤中已经将数据存储到结构体中了,那么这里开始实际调用JAVA的函数了。
假设,这里被调用的函数名叫做:RecordDataAndroidBack(数组,bool类型)
jclass objClass = mJni->FindClass("cn/test/model/java2so/event/DataSt");1
代码解析:
出现函数调用错误时,最容易出现的问题就是JAVA函数参数的路径写的不对,或者是格式不正确,90%都是在第三个参数上出问题的,而且,有些问题还会跑偏,让你抓狂,让你无处可找!!
到这里,如何调用带有结构体容器的JAVA函数已经讲解完成了,小伙伴们尽情的尝试吧!
我是中国好公民st,一名C++开发程序猿~
原文:https://juejin.cn/post/7102361188113055752