写点什么

JNI 中实现类似 C++ 回调方法 - 结构体操作

  • 2022-10-25
    河北
  • 本文字数:1902 字

    阅读完需:约 6 分钟

JNI中实现类似C++回调方法-结构体操作

上篇文章讲述了 JNI 中 C++简单的调用 Java 函数,接下来我们要解决上次留下的疑惑问题进行解答,如何调用带有结构体的 java 函数。


假设:C++要给 Java 传入一个叫做 DataSt 的结构体,那么,Android 也需要定义同样的结构体,保持与 so 文件中的结构体名称以及字段保持一致,否则查询不到。


结构体内容如下:

struct DataSt{    std::string id;    std::vector<int> vetIndex;}
复制代码

C++传入的数据保存在:std::vector<DataSt> 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

3.1:获取 id 方法 ID

jmethodID method_id = mJni->GetMethodID(objClass, "setId", "(Ljava/lang/String;)V");
复制代码

3.2:获取 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 操作,我们进行具体的代码展示吧!

5.1:将 id 数据设置到 objmodel 对象中

第一步:string 转成 jstring 类型

jstring jsId = mJni->NewStringUTF(stInfo.id.c_str());
复制代码

第二步:存储到 objmodel 对象中

mJni->CallVoidMethod(objmodel, method_id, jname);
复制代码

5.2:将 vetIndex 数据设置到 objmodel 对象中

for(int n = 0; n < stInfo.vetIndex.size(); n++){    int nIndex = stInfo.vetIndex[n];    mJni->CallVoidMethod(objmodel, method_index, nIndex);}
复制代码

6:C++调用 Java 函数传递参数

第五步骤中已经将数据存储到结构体中了,那么这里开始实际调用 JAVA 的函数了。

假设,这里被调用的函数名叫做:RecordDataAndroidBack(数组,bool 类型)

jmethodID mid;mid = mJni->GetMethodID(cls, "RecordDataAndroidBack", "([Lcn/test/model/java2so/event/DataSt;Z)V");if(mid == nullptr){    //函数调用错误!    return;}//调用成功后,将容器arrayData中的数据传入函数汇总mJni->CallVoidMethod(mThiz, mid, arrayData, bres);
复制代码

代码解析:

出现函数调用错误时,最容易出现的问题就是 JAVA 函数参数的路径写的不对,或者是格式不正确,90%都是在第三个参数上出问题的,而且,有些问题还会跑偏,让你抓狂,让你无处可找!!


到这里,如何调用带有结构体容器的 JAVA 函数已经讲解完成了,小伙伴们尽情的尝试吧!


我是中国好公民 st,一名 C++开发程序媛~

发布于: 2022-10-25阅读数: 16
用户头像

书山有路勤为径,学海无涯苦作舟 2022-07-01 加入

擅长语言:C++ 涉及语言:Python

评论

发布
暂无评论
JNI中实现类似C++回调方法-结构体操作_c++_中国好公民st_InfoQ写作社区