|  | 
				
					
	
		
			
 			Posted on 2013-11-24 13:04 虚空骄阳  阅读(6625) 评论(1)  编辑 收藏 引用   所属分类: Android   介绍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 方法: public class DataProvider {      // 两个java中的int 传递c 语言 ,  c语言处理这个相加的逻辑,把相加的结果返回给java      public native int add(int x ,int y);            //把一个java中的字符串传递给c语言, c 语言处理下字符串, 处理完毕返回给java       public native String sayHelloInC(String s);        //把一个java中int类型的数组传递给c语言, c语言里面把数组的每一个元素的值 都增加5,       //然后在把处理完毕的数组,返回给java      public native int[] intMethod(int[] iNum);   }  
以上方法要在C中实现的头文件,头文件可以理解为要在C中实现的方法
 其中 JENEnv* 代表的是java环境 , 通过这个环境可以调用java的方法,jobject 表示哪个对象调用了 这个c语言的方法, thiz就表示的是当前的对象 /* DO NOT EDIT THIS FILE - it is machine generated */  #include <jni.h>  /* Header for class cn_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  */  JNIEXPORT jint JNICALL Java_cn_itcast_ndk3_DataProvider_add    (JNIEnv *, jobject, jint, jint);    /*  * Class:     cn_itcast_ndk3_DataProvider  * Method:    sayHelloInC  * Signature: (Ljava/lang/String;)Ljava/lang/String;  */  JNIEXPORT jstring JNICALL Java_cn_itcast_ndk3_DataProvider_sayHelloInC    (JNIEnv *, jobject, jstring);    /*  * Class:     cn_itcast_ndk3_DataProvider  * Method:    intMethod  * Signature: ([I)[I  */  JNIEXPORT jintArray JNICALL Java_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中的值  #define LOG_TAG "logfromc"  //日志显示的等级  #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)  #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)    // java中的jstring, 转化为c的一个字符数组  char*   Jstring2CStr(JNIEnv*   env,   jstring   jstr)  {       char*   rtn   =   NULL;       jclass   clsstring   =   (*env)->FindClass(env,"java/lang/String");       jstring   strencode   =   (*env)->NewStringUTF(env,"GB2312");       jmethodID   mid   =   (*env)->GetMethodID(env,clsstring,   "getBytes",   "(Ljava/lang/String;)[B");       jbyteArray   barr=   (jbyteArray)(*env)->CallObjectMethod(env,jstr,mid,strencode); // String .getByte("GB2312");       jsize   alen   =   (*env)->GetArrayLength(env,barr);       jbyte*   ba   =   (*env)->GetByteArrayElements(env,barr,JNI_FALSE);       if(alen   >   0)       {        rtn   =   (char*)malloc(alen+1);         //new   char[alen+1]; "\0"        memcpy(rtn,ba,alen);        rtn[alen]=0;       }       (*env)->ReleaseByteArrayElements(env,barr,ba,0);  //释放内存         return rtn;  }    //处理整形相加  JNIEXPORT jint JNICALL Java_cn_itcast_ndk3_DataProvider_add    (JNIEnv * env, jobject obj, jint x, jint y){      //打印 java 传递过来的 jstring ;      LOGI("log from c code ");      LOGI("x= %ld",x);      LOGD("y= %ld",y);      return x+y;  }    //处理字符串追加  JNIEXPORT jstring JNICALL Java_cn_itcast_ndk3_DataProvider_sayHelloInC    (JNIEnv * env, jobject obj, jstring str){        char* p =  Jstring2CStr(env,str);      LOGI("%s",p);      char* newstr = "append string";        //strcat(dest, sorce) 把sorce字符串添加到dest字符串的后面      LOGI("END");      return (*env)->NewStringUTF(env, strcat(p,newstr));  }    //处理数组中的每一个元素  JNIEXPORT jintArray JNICALL Java_cn_itcast_ndk3_DataProvider_intMethod    (JNIEnv * env, jobject obj, jintArray arr){      // 1.获取到 arr的大小        int len = (*env)->GetArrayLength(env, arr);      LOGI("len=%d", len);        if(len==0){          return arr;      }      //取出数组中第一个元素的内存地址      jint* p = (*env)-> GetIntArrayElements(env,arr,0);      int i=0;      for(;i<len;i++){          LOGI("len=%ld", *(p+i));//取出的每个元素          *(p+i) += 5; //取出的每个元素加五      }      return arr;  }  
编写Android.mk文件 LOCAL_PATH := $(call my-dir)    include $(CLEAR_VARS)    LOCAL_MODULE    := Hello  LOCAL_SRC_FILES := Hello.c   #增加 log 函数对应的log 库  liblog.so  libthread_db.a  LOCAL_LDLIBS += -llog    include $(BUILD_SHARED_LIBRARY)  
 Java代码load 动态库.调用native代码 static{          System.loadLibrary("Hello");      }      DataProvider dp;            @Override      public void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.main);          dp = new DataProvider();      }            //add对应的事件      public void add(View view){          //执行C语言处理数据          int result = dp.add(3, 5);          Toast.makeText(this, "相加的结果"+ result, 1).show();          }  
  C中回调java方法 声明native 方法: public class DataProvider{      public native void callCcode();      public native void callCcode1();      public native void callCcode2();            ///C调用java中的空方法        public void helloFromJava(){          System.out.println("hello from java ");      }      //C调用java中的带两个int参数的方法      public int Add(int x,int y){          System.out.println("相加的结果为"+ (x+y));          return x+y;      }      //C调用java中参数为string的方法      public void printString(String s){          System.out.println("in java code "+ s);      }  }  
头文件可以用jdk自带的javah进行自动生成,使用javap -s可以获取到方法的签名。 C代码实现回调需要三个步骤:首先要要获取到 某个对象 , 然后获取对象里面的方法  ,最后 调用这个方法  . #include "cn_itcast_ndk4_DataProvider.h"  #include <string.h>  #include <android/log.h>  #define LOG_TAG "logfromc"  #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)  #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)    //1.调用java中的无参helloFromJava方法  JNIEXPORT void JNICALL Java_cn_itcast_ndk4_DataProvider_callCcode    (JNIEnv * env , jobject obj){      // 获取到DataProvider对象      char* classname = "cn/itcast/ndk4/DataProvider";      jclass dpclazz = (*env)->FindClass(env,classname);      if (dpclazz == 0) {              LOGI("not find class!");          } else              LOGI("find class");      //第三个参数 和第四个参数 是方法的签名,第三个参数是方法名  , 第四个参数是根据返回值和参数生成的      //获取到DataProvider要调用的方法      jmethodID methodID = (*env)->GetMethodID(env,dpclazz,"helloFromJava","()V");      if (methodID == 0) {              LOGI("not find method!");          } else              LOGI("find method");      //调用这个方法      (*env)->CallVoidMethod(env, obj,methodID);  }    // 2.调用java中的printString方法传递一个字符串  JNIEXPORT void JNICALL Java_cn_itcast_ndk4_DataProvider_callCcode1    (JNIEnv * env, jobject obj){      LOGI("in code");      // 获取到DataProvider对象      char* classname = "cn/itcast/ndk4/DataProvider";      jclass dpclazz = (*env)->FindClass(env,classname);      if (dpclazz == 0) {              LOGI("not find class!");          } else              LOGI("find class");      // 获取到要调用的method      jmethodID methodID = (*env)->GetMethodID(env,dpclazz,"printString","(Ljava/lang/String;)V");      if (methodID == 0) {              LOGI("not find method!");          } else              LOGI("find method");        //调用这个方法      (*env)->CallVoidMethod(env, obj,methodID,(*env)->NewStringUTF(env,"haha"));  }    // 3. 调用java中的add方法 , 传递两个参数 jint x,y  JNIEXPORT void JNICALL Java_cn_itcast_ndk4_DataProvider_callCcode2    (JNIEnv * env, jobject obj){      char* classname = "cn/itcast/ndk4/DataProvider";      jclass dpclazz = (*env)->FindClass(env,classname);      jmethodID methodID = (*env)->GetMethodID(env,dpclazz,"Add","(II)I");      (*env)->CallIntMethod(env, obj,methodID,3l,4l);  }  
 
	    
    
Feedback
				
					
						# re: Android使用JNI实现Java与C之间传递数据  回复  更多评论
						  
					
					2016-03-04 14:59 by 
				 fff |