在讲正题之前,先说一下C++,JNI和Java 对应的数据类型对比吧,废话不多说,直接上图
上面为C++,Java,JNI 三者只见对应的数据类型
好了,现在我们有了上面的数据类型比对,下面就讲讲从C++如何将数据传递给Java吧
1,如果想要从C层,传递信息给Java,那首先需要在java层定义一个方法,用来接收从C层传递过来的信息,例如
public void onEvStationRoute(int count,boolean isTrue,
long handlerID,Route route,
EvExpectedRange evExpectedRange){
}
上面就是在java层定义的一个方法,用来接收C++层的数据信息,上面的方法中,有四个参数,分别是int类型,boolean类型,Object类型,此处特别声明一点,EvExpecteRange 内部我特意定义两种数据类型,List和Date(时间),后面会细讲。
2,定义完java层后,我们就需要在C层做手脚了。首先,想要与java端通信,需要获取一个唯一的id,在C++里面,想要与Java通信,肯定离不开JNI,所以,这个唯一的ID,我们就把他称为jmethodID。
代码如下
jmethodID m_route_ev_station = env->GetMethodID(routerClass, "onEvStationRoute",
"(IZJLcom/auto/navigation/routing/Route;Lcom/auto/navigation/routing/EvExpectedRange;)V");
解释一下上面的GetMethodId的几个参数。
第一个参数是需要知道方法所在的类,获取的方法如下
jobject m_router_obj = env->NewGlobalRef( instance );//instance是从JNI层传过来的Jobject
jclass routerClass = env->GetObjectClass( m_router_obj );
此时,得到了需要通信的方法所在的类。
第二个参数是我们之前在java层定义的方法名。第三个参数,就是我们方法中的几个形参的数据类型,可以看到我们在java中定义的参数类型顺序依此是int,boolean,long,object,object,那对应的c++类型则是上方定义的几个数据类型,需要说明一下,object的类型,是在java中定义的几个bean类,类似于json信息的解析。此处分别定义了Route和EvExpectedRange两个bean类。
3,好了,定义好方法的唯一ID之后,我们就需要考了一下如何使用他了。代码如下:
jenv->CallVoidMethod(m_router_obj, m_route_ev_station,
(jlong)id,
(jint) count,
(jboolean) isTrue,
routeObj,
routeEvRangeObj);
解释一下上方的代码,
首先jenv,他是JNI中独有一种对象JNIEnv,内部封装了很多很多的方法,感兴趣的同学,可以去看一下他的源码,我们在这里就不解释了,直接看看如何拿到他吧。
JNIEnv *jenv;
// Get the Environment status.
int getEnvStat = gJavaVM->GetEnv((void **) &jenv, JNI_VERSION_1_6);
// If current is not attached to main thread, attache it.
if (getEnvStat != JNI_OK) {
gJavaVM->AttachCurrentThread(&jenv, nullptr);
}
切记,通过以上代码就可以得到jenv的对象指针,但是一定要判断getEnvStart的状态,考虑到线程的合并问题,就是第五行和第六行的内容。如果不加这两句话,多线程出现的情况下,很有可能会崩溃的。
拿到jenv对象指针后,调用CallVoidMethod方法,传入参数就可以将需要的信息传递给java层了。是不是很简单?别急,我们还没有说callVoidMethod内部的几个参数呢。
第一个参数,就是一个jobject对象,这个对象是从该方法对应的java类传过来的,上面我们已经说过m_router_obj是怎么来的了。
第二个参数,我们也讲过他的来历了,他是唯一的方法标识ID
第三个参数到第五个参数,都是基础的数据类型,这里我们可以将基础的数据类型直接强转一下,C++和JNI是可以接收这样的方式的
重点来了,我们如何传递jobject数据类型,即我们怎么传递第六个参数和第七个参数?请看第二篇博客哦。