android(NDK+JNI)---Android使用JNI实现Java与C之间传递数据
转自:http://blog.csdn.net/furongkang/article/details/6857610
介绍Java如何将数据传递给C和C回调Java的方法。 java传递数据给C,在C代码中进行处理数据,处理完数据后返回给java。C的回调是Java传递数据给C,C需要用到Java中的某个方法,就需要调用java的方法。
Android中使用JNI七个步骤:
1.创建一个android工程
2.JAVA代码中写声明native 方法 public native String helloFromJNI();
3.用javah工具生成头文件
4. 创建jni目录,引入头文件,根据头文件实现c代码
5.编写Android.mk文件
6.Ndk编译生成动态库
7.Java代码load 动态库.调用native代码
Java调用C进行数据传递
这里分别传递整形、字符串、数组在C中进行处理。
声明native 方法:
- publicclassDataProvider{
- //两个java中的int传递c语言,c语言处理这个相加的逻辑,把相加的结果返回给java
- publicnativeintadd(intx,inty);
- //把一个java中的字符串传递给c语言,c语言处理下字符串,处理完毕返回给java
- publicnativeStringsayHelloInC(Strings);
- //把一个java中int类型的数组传递给c语言,c语言里面把数组的每一个元素的值都增加5,
- //然后在把处理完毕的数组,返回给java
- publicnativeint[]intMethod(int[]iNum);
- }
以上方法要在C中实现的头文件,头文件可以理解为要在C中实现的方法
其中 JENEnv* 代表的是java环境 , 通过这个环境可以调用java的方法,jobject 表示哪个对象调用了 这个c语言的方法, thiz就表示的是当前的对象
- /*DONOTEDITTHISFILE-itismachinegenerated*/
- #include<jni.h>
- /*Headerforclasscn_itcast_ndk3_DataProvider*/
- #ifndef_Included_cn_itcast_ndk3_DataProvider
- #define_Included_cn_itcast_ndk3_DataProvider
- #ifdef__cplusplus
- extern"C"{
- #endif
- /*
- *Class:cn_itcast_ndk3_DataProvider
- *Method:add
- *Signature:(II)I
- */
- JNIEXPORTjintJNICALLJava_cn_itcast_ndk3_DataProvider_add
- (JNIEnv*,jobject,jint,jint);
- /*
- *Class:cn_itcast_ndk3_DataProvider
- *Method:sayHelloInC
- *Signature:(Ljava/lang/String;)Ljava/lang/String;
- */
- JNIEXPORTjstringJNICALLJava_cn_itcast_ndk3_DataProvider_sayHelloInC
- (JNIEnv*,jobject,jstring);
- /*
- *Class:cn_itcast_ndk3_DataProvider
- *Method:intMethod
- *Signature:([I)[I
- */
- JNIEXPORTjintArrayJNICALLJava_cn_itcast_ndk3_DataProvider_intMethod
- (JNIEnv*,jobject,jintArray);
- #ifdef__cplusplus
- }
- #endif
- #endif
C代码出了要引用头文件外,还要引入日志信息,以方便在C 中进行调试
- //引入头文件
- #include"cn_itcast_ndk3_DataProvider.h"
- #include<string.h>
- //导入日志头文件
- #include<android/log.h>
- //修改日志tag中的值
- #defineLOG_TAG"logfromc"
- //日志显示的等级
- #defineLOGD(...)__android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
- #defineLOGI(...)__android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
- //java中的jstring,转化为c的一个字符数组
- char*Jstring2CStr(JNIEnv*env,jstringjstr)
- {
- char*rtn=NULL;
- jclassclsstring=(*env)->FindClass(env,"java/lang/String");
- jstringstrencode=(*env)->NewStringUTF(env,"GB2312");
- jmethodIDmid=(*env)->GetMethodID(env,clsstring,"getBytes","(Ljava/lang/String;)[B");
- jbyteArraybarr=(jbyteArray)(*env)->CallObjectMethod(env,jstr,mid,strencode);//String.getByte("GB2312");
- jsizealen=(*env)->GetArrayLength(env,barr);
- jbyte*ba=(*env)->GetByteArrayElements(env,barr,JNI_FALSE);
- if(alen>0)
- {
- rtn=(char*)malloc(alen+1);//newchar[alen+1];"\0"
- memcpy(rtn,ba,alen);
- rtn[alen]=0;
- }
- (*env)->ReleaseByteArrayElements(env,barr,ba,0);//释放内存
- returnrtn;
- }
- //处理整形相加
- JNIEXPORTjintJNICALLJava_cn_itcast_ndk3_DataProvider_add
- (JNIEnv*env,jobjectobj,jintx,jinty){
- //打印java传递过来的jstring;
- LOGI("logfromccode");
- LOGI("x=%ld",x);
- LOGD("y=%ld",y);
- returnx+y;
- }
- //处理字符串追加
- JNIEXPORTjstringJNICALLJava_cn_itcast_ndk3_DataProvider_sayHelloInC
- (JNIEnv*env,jobjectobj,jstringstr){
- char*p=Jstring2CStr(env,str);
- LOGI("%s",p);
- char*newstr="appendstring";
- //strcat(dest,sorce)把sorce字符串添加到dest字符串的后面
- LOGI("END");
- return(*env)->NewStringUTF(env,strcat(p,newstr));
- }
- //处理数组中的每一个元素
- JNIEXPORTjintArrayJNICALLJava_cn_itcast_ndk3_DataProvider_intMethod
- (JNIEnv*env,jobjectobj,jintArrayarr){
- //1.获取到arr的大小
- intlen=(*env)->GetArrayLength(env,arr);
- LOGI("len=%d",len);
- if(len==0){
- returnarr;
- }
- //取出数组中第一个元素的内存地址
- jint*p=(*env)->GetIntArrayElements(env,arr,0);
- inti=0;
- for(;i<len;i++){
- LOGI("len=%ld",*(p+i));//取出的每个元素
- *(p+i)+=5;//取出的每个元素加五
- }
- returnarr;
- }
编写Android.mk文件
- LOCAL_PATH:=$(callmy-dir)
- include$(CLEAR_VARS)
- LOCAL_MODULE:=Hello
- LOCAL_SRC_FILES:=Hello.c
- #增加log函数对应的log库liblog.solibthread_db.a
- LOCAL_LDLIBS+=-llog
- include$(BUILD_SHARED_LIBRARY)
Java代码load 动态库.调用native代码
- static{
- System.loadLibrary("Hello");
- }
- DataProviderdp;
- @Override
- publicvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- dp=newDataProvider();
- }
- //add对应的事件
- publicvoidadd(Viewview){
- //执行C语言处理数据
- intresult=dp.add(3,5);
- Toast.makeText(this,"相加的结果"+result,1).show();
- }
C中回调java方法
声明native 方法:
- publicclassDataProvider{
- publicnativevoidcallCcode();
- publicnativevoidcallCcode1();
- publicnativevoidcallCcode2();
- ///C调用java中的空方法
- publicvoidhelloFromJava(){
- System.out.println("hellofromjava");
- }
- //C调用java中的带两个int参数的方法
- publicintAdd(intx,inty){
- System.out.println("相加的结果为"+(x+y));
- returnx+y;
- }
- //C调用java中参数为string的方法
- publicvoidprintString(Strings){
- System.out.println("injavacode"+s);
- }
- }
头文件可以用jdk自带的javah进行自动生成,使用javap -s可以获取到方法的签名。
C代码实现回调需要三个步骤:首先要要获取到 某个对象 , 然后获取对象里面的方法 ,最后 调用这个方法 .
- #include"cn_itcast_ndk4_DataProvider.h"
- #include<string.h>
- #include<android/log.h>
- #defineLOG_TAG"logfromc"
- #defineLOGD(...)__android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
- #defineLOGI(...)__android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
- //1.调用java中的无参helloFromJava方法
- JNIEXPORTvoidJNICALLJava_cn_itcast_ndk4_DataProvider_callCcode
- (JNIEnv*env,jobjectobj){
- //获取到DataProvider对象
- char*classname="cn/itcast/ndk4/DataProvider";
- jclassdpclazz=(*env)->FindClass(env,classname);
- if(dpclazz==0){
- LOGI("notfindclass!");
- }else
- LOGI("findclass");
- //第三个参数和第四个参数是方法的签名,第三个参数是方法名,第四个参数是根据返回值和参数生成的
- //获取到DataProvider要调用的方法
- jmethodIDmethodID=(*env)->GetMethodID(env,dpclazz,"helloFromJava","()V");
- if(methodID==0){
- LOGI("notfindmethod!");
- }else
- LOGI("findmethod");
- //调用这个方法
- (*env)->CallVoidMethod(env,obj,methodID);
- }
- //2.调用java中的printString方法传递一个字符串
- JNIEXPORTvoidJNICALLJava_cn_itcast_ndk4_DataProvider_callCcode1
- (JNIEnv*env,jobjectobj){
- LOGI("incode");
- //获取到DataProvider对象
- char*classname="cn/itcast/ndk4/DataProvider";
- jclassdpclazz=(*env)->FindClass(env,classname);
- if(dpclazz==0){
- LOGI("notfindclass!");
- }else
- LOGI("findclass");
- //获取到要调用的method
- jmethodIDmethodID=(*env)->GetMethodID(env,dpclazz,"printString","(Ljava/lang/String;)V");
- if(methodID==0){
- LOGI("notfindmethod!");
- }else
- LOGI("findmethod");
- //调用这个方法
- (*env)->CallVoidMethod(env,obj,methodID,(*env)->NewStringUTF(env,"haha"));
- }
- //3.调用java中的add方法,传递两个参数jintx,y
- JNIEXPORTvoidJNICALLJava_cn_itcast_ndk4_DataProvider_callCcode2
- (JNIEnv*env,jobjectobj){
- char*classname="cn/itcast/ndk4/DataProvider";
- jclassdpclazz=(*env)->FindClass(env,classname);
- jmethodIDmethodID=(*env)->GetMethodID(env,dpclazz,"Add","(II)I");
- (*env)->CallIntMethod(env,obj,methodID,3l,4l);
- }
转自:http://blog.csdn.net/furongkang/article/details/6857610
更多相关文章
- 浅谈Java中Collections.sort对List排序的两种方法
- Python list sort方法的具体使用
- python list.sort()根据多个关键字排序的方法实现
- Android逆向之旅---Android中的sharedUserId属性详解
- android利用JNI调用C++自定义类
- android http
- 如何使用SharedPerferences
- Android(安卓)照相机打开方法
- android onRestoreInstanceState调用时序