这篇文章主要讲Java通过jni调用c层时如何传递参数,如何在c的代码中回调Java的方法
上一篇 Android studio下jni的配置和第一个hello word程序
在上一个例子的基础上继续研究如何通过jni传递参数给c,其实传递参数很简单,先说一下步骤:
1、在Java中定义native的含参的方法
2、使用javah生成头文件
3、在头文件中找到我们含参的方法,并在c中完善它的方法体,返回c最终的处理结果
下面一步一步来详细说明:
public class JNIUtil { //直接从c获取一个字符串 public native String getStringFromC(); //传递int类型的参数给c,c返回处理结果 public native int addNum(int x, int y); //传递String类型的参数给C 处理一下返回来 public native String sayFromC(String s); //传递int类型的数组给C public native int[] arrElementsIncrease(int[] intArray); }然后打开Android studio 自带的Terminal,进入app/src/main 目录下,使用如下命令:
javah -d jni -classpath D:\android_studio\sdk\platforms\android-23\android.jar;..\..\build\intermediates\classes\debug com.zhaocd.activity.myjnidemo1.JNIUtil
即可生成头文件com_zhaocd_activity_myjnidemo1_JNIUtil.h (注意:在JNIUtil中新增了方法后,必须先build -> rebuild preject 一下,不然class文件还是以前的,生成的头文件中也没有新增的方法)
打开头文件,找到我们定义的native的几个方法,然后将它们复制到hello.c的c文件中,完善方法体:
/** * 返回两个int类型变量的和 */ JNIEXPORT jint JNICALL Java_com_zhaocd_activity_myjnidemo1_JNIUtil_addNum (JNIEnv * env, jobject obj, jint x, jint y){ return x+y; }
为了篇幅的长度,这里只贴出一个方法,因为我们的重点不是c的编写,需要源码的可以在文章末尾下载。
可能大家也注意到了,int对应的jint,string对应的jstring ,其实这些基本的数据类型都是在jni.h这个文件中定义好的
# include <inttypes.h> /* C99 */ typedef uint8_t jboolean; /* unsigned 8 bits */ typedef int8_t jbyte; /* signed 8 bits */ typedef uint16_t jchar; /* unsigned 16 bits */ typedef int16_t jshort; /* signed 16 bits */ typedef int32_t jint; /* signed 32 bits */ typedef int64_t jlong; /* signed 64 bits */ typedef float jfloat; /* 32-bit IEEE 754 */ typedef double jdouble; /* 64-bit IEEE 754 */ #else typedef unsigned char jboolean; /* unsigned 8 bits */ typedef signed char jbyte; /* signed 8 bits */ typedef unsigned short jchar; /* unsigned 16 bits */ typedef short jshort; /* signed 16 bits */ typedef int jint; /* signed 32 bits */ typedef long long jlong; /* signed 64 bits */ typedef float jfloat; /* 32-bit IEEE 754 */ typedef double jdouble; /* 64-bit IEEE 754 */ #endif /* "cardinal indices and sizes" */一个整形,你定义成int,在生成头文件的时候jni自动会给你转换成jint,知道这个的话就可以无视那个“j”了,ndk会把Java的数据类型和c的数据类型进行转换。
除了基本的数据类型,肯定还有数组了
typedef void* jobject; typedef jobject jclass; typedef jobject jstring; typedef jobject jarray; typedef jarray jobjectArray; typedef jarray jbooleanArray; typedef jarray jbyteArray; typedef jarray jcharArray; typedef jarray jshortArray; typedef jarray jintArray; typedef jarray jlongArray; typedef jarray jfloatArray; typedef jarray jdoubleArray; typedef jobject jthrowable; typedef jobject jweak;可以看到不管是什么类型的数组,都是先转换成jarray -> jobject -> void* 。 void*是一种特别的指针,说它特别是因为它不能判断出数据的类型,或者说根据这个类型不能判断出指向对象的长度。
由于我们开发项目时,一般很少自己去写c层的代码,而是使用一些开源的现成的类库或者由c++工程师写,所以这里就不对c做深入的研究了~~~~