android jni 返值

今天,简单讲讲如何在jni内把结果返回给java端。

一。使用Integer类作为返回值参数传入jni。

最近在开发jni时,需要返回多个参数给java。这个过程中,碰到了一些问题,值得探讨一下。

 具体是这样,jni方法jni_do_something作了底层处理后,得出两个int数据,需要将他们的值传递给java。在C语言中,直接用指针就可以了。Java中可以传递两个Integer的引用。用JNI怎么实现呢?我在android frameworks源代码中看了一下,对于类似传值需求,android都是在java层自定义了一个class,用来封装各个需要传递的参数。jni中需要修改时,获得该class的成员id,然后用SetIntField来修改。
 我不想这么做,因为类似的native方法比较多,我总不能每次都定义结构体吧,而且将不同方法的参数封装在一个class中,也不太对,因为它们没有共同意义。
为了让jni能修改,Java层毫无疑问需要传入Integer类型参数,这样jni才认为它是一个jobject,才可以修改。好的,问题出现了。jni方法实现:jni_do_something(JNIEnv *env, jobject thiz, jobject p1, jobject p2) { jclass c; jfieldID id; c = env->FindClass("java/lang/Integer"); if (c==NULL) { LOGD("FindClass failed"); return -1; } id = env->GetFieldID(c, "value", "I"); if (id==NULL) { LOGD("GetFiledID failed"); return -1; } env->SetIntField(p1, id, 5); env->SetIntField(p2, id, 10); return 0;}

java层调用如果这样写:

native int do_something(Integer p1, Integer p2);Integer p1=0, p2=0;do_something(p1, p2);Log.d("test", "p1: "+p1);Log.d("test", "p2: "+p2);

这样打印出的值是(10,10),而不是期望的(5,10)。为什么呢?

我在stackoverflow上发了一个贴,大家众说纷纭。有的说跟mutable/imutable object有关,有的说跟autoboxing有关。我再次做了试验。如果写成Integer p1=0, p2=1;

或者:

Integer p1 = new Integer(0);Integer p2= new Integer(0);

原来,这跟autoboxing有关。当你用Integer p1 = 0这种方式时,java使用autoboxing机制将0封装在一个Integer对象中,这时使用了Integer类的valueOf方法。在java 语言中,有一个很诡异的现象,对于在-128~127间的小数字,会在static pool中返回一个静态对象,在这个范围外的,会new一个Integer。

二.使用int数组作为返回值传入jni。

JNIEXPORT jint JNICALL Java_com_p2p_h265_1api_HWH265_1GetWidth_1APIs_h264ParseSequenceParameterSet (JNIEnv *env, jclass, jbyteArray pdata, jint nSps, jintArray out_4para, jint nsps_buf_offset){

其中out_4para是java端传入的新建的长度为2的数组。

int * para_size = (int*) (env)->GetIntArrayElements(out_4para, 0);para_size[0] = params.pic_width;para_size[1] = params.pic_height;(env)->ReleaseIntArrayElements(out_4para, para_size, 0);

这样,java端就收到了jni传递的值。

android jni 返值就讲完了。

就这么简单。