`

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 方法:

[java] view plaincopy
 
  1. public class DataProvider {  
  2.     // 两个java中的int 传递c 语言 ,  c语言处理这个相加的逻辑,把相加的结果返回给java  
  3.     public native int add(int x ,int y);  
  4.       
  5.     //把一个java中的字符串传递给c语言, c 语言处理下字符串, 处理完毕返回给java   
  6.     public native String sayHelloInC(String s);  
  7.   
  8.     //把一个java中int类型的数组传递给c语言, c语言里面把数组的每一个元素的值 都增加5,   
  9.     //然后在把处理完毕的数组,返回给java  
  10.     public native int[] intMethod(int[] iNum);   
  11. }  


以上方法要在C中实现的头文件,头文件可以理解为要在C中实现的方法

其中 JENEnv* 代表的是java环境 , 通过这个环境可以调用java的方法,jobject 表示哪个对象调用了 这个c语言的方法, thiz就表示的是当前的对象

[cpp] view plaincopy
 
  1. /* DO NOT EDIT THIS FILE - it is machine generated */  
  2. #include <jni.h>  
  3. /* Header for class cn_itcast_ndk3_DataProvider */  
  4.   
  5. #ifndef _Included_cn_itcast_ndk3_DataProvider  
  6. #define _Included_cn_itcast_ndk3_DataProvider  
  7. #ifdef __cplusplus  
  8. extern "C" {  
  9. #endif  
  10. /* 
  11.  * Class:     cn_itcast_ndk3_DataProvider 
  12.  * Method:    add 
  13.  * Signature: (II)I 
  14.  */  
  15. JNIEXPORT jint JNICALL Java_cn_itcast_ndk3_DataProvider_add  
  16.   (JNIEnv *, jobject, jint, jint);  
  17.   
  18. /* 
  19.  * Class:     cn_itcast_ndk3_DataProvider 
  20.  * Method:    sayHelloInC 
  21.  * Signature: (Ljava/lang/String;)Ljava/lang/String; 
  22.  */  
  23. JNIEXPORT jstring JNICALL Java_cn_itcast_ndk3_DataProvider_sayHelloInC  
  24.   (JNIEnv *, jobject, jstring);  
  25.   
  26. /* 
  27.  * Class:     cn_itcast_ndk3_DataProvider 
  28.  * Method:    intMethod 
  29.  * Signature: ([I)[I 
  30.  */  
  31. JNIEXPORT jintArray JNICALL Java_cn_itcast_ndk3_DataProvider_intMethod  
  32.   (JNIEnv *, jobject, jintArray);  
  33.   
  34. #ifdef __cplusplus  
  35. }  
  36. #endif  
  37. #endif  


C代码出了要引用头文件外,还要引入日志信息,以方便在C 中进行调试

[cpp] view plaincopy
 
  1. //引入头文件  
  2. #include "cn_itcast_ndk3_DataProvider.h"  
  3. #include <string.h>  
  4. //导入日志头文件  
  5. #include <android/log.h>  
  6. //修改日志tag中的值  
  7. #define LOG_TAG "logfromc"  
  8. //日志显示的等级  
  9. #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)  
  10. #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)  
  11.   
  12. // java中的jstring, 转化为c的一个字符数组  
  13. char*   Jstring2CStr(JNIEnv*   env,   jstring   jstr)  
  14. {  
  15.      char*   rtn   =   NULL;  
  16.      jclass   clsstring   =   (*env)->FindClass(env,"java/lang/String");  
  17.      jstring   strencode   =   (*env)->NewStringUTF(env,"GB2312");  
  18.      jmethodID   mid   =   (*env)->GetMethodID(env,clsstring,   "getBytes",   "(Ljava/lang/String;)[B");  
  19.      jbyteArray   barr=   (jbyteArray)(*env)->CallObjectMethod(env,jstr,mid,strencode); // String .getByte("GB2312");  
  20.      jsize   alen   =   (*env)->GetArrayLength(env,barr);  
  21.      jbyte*   ba   =   (*env)->GetByteArrayElements(env,barr,JNI_FALSE);  
  22.      if(alen   >   0)  
  23.      {  
  24.       rtn   =   (char*)malloc(alen+1);         //new   char[alen+1]; "\0"  
  25.       memcpy(rtn,ba,alen);  
  26.       rtn[alen]=0;  
  27.      }  
  28.      (*env)->ReleaseByteArrayElements(env,barr,ba,0);  //释放内存  
  29.   
  30.      return rtn;  
  31. }  
  32.   
  33. //处理整形相加  
  34. JNIEXPORT jint JNICALL Java_cn_itcast_ndk3_DataProvider_add  
  35.   (JNIEnv * env, jobject obj, jint x, jint y){  
  36.     //打印 java 传递过来的 jstring ;  
  37.     LOGI("log from c code ");  
  38.     LOGI("x= %ld",x);  
  39.     LOGD("y= %ld",y);  
  40.     return x+y;  
  41. }  
  42.   
  43. //处理字符串追加  
  44. JNIEXPORT jstring JNICALL Java_cn_itcast_ndk3_DataProvider_sayHelloInC  
  45.   (JNIEnv * env, jobject obj, jstring str){  
  46.   
  47.     char* p =  Jstring2CStr(env,str);  
  48.     LOGI("%s",p);  
  49.     char* newstr = "append string";  
  50.   
  51.     //strcat(dest, sorce) 把sorce字符串添加到dest字符串的后面  
  52.     LOGI("END");  
  53.     return (*env)->NewStringUTF(env, strcat(p,newstr));  
  54. }  
  55.   
  56. //处理数组中的每一个元素  
  57. JNIEXPORT jintArray JNICALL Java_cn_itcast_ndk3_DataProvider_intMethod  
  58.   (JNIEnv * env, jobject obj, jintArray arr){  
  59.     // 1.获取到 arr的大小  
  60.   
  61.     int len = (*env)->GetArrayLength(env, arr);  
  62.     LOGI("len=%d", len);  
  63.   
  64.     if(len==0){  
  65.         return arr;  
  66.     }  
  67.     //取出数组中第一个元素的内存地址  
  68.     jint* p = (*env)-> GetIntArrayElements(env,arr,0);  
  69.     int i=0;  
  70.     for(;i<len;i++){  
  71.         LOGI("len=%ld", *(p+i));//取出的每个元素  
  72.         *(p+i) += 5; //取出的每个元素加五  
  73.     }  
  74.     return arr;  
  75. }  

编写Android.mk文件

[cpp] view plaincopy
 
  1. LOCAL_PATH := $(call my-dir)  
  2.   
  3. include $(CLEAR_VARS)  
  4.   
  5. LOCAL_MODULE    := Hello  
  6. LOCAL_SRC_FILES := Hello.c   
  7. #增加 log 函数对应的log 库  liblog.so  libthread_db.a  
  8. LOCAL_LDLIBS += -llog  
  9.   
  10. include $(BUILD_SHARED_LIBRARY)  

 Java代码load 动态库.调用native代码

[java] view plaincopy
 
  1. static{  
  2.         System.loadLibrary("Hello");  
  3.     }  
  4.     DataProvider dp;  
  5.       
  6.     @Override  
  7.     public void onCreate(Bundle savedInstanceState) {  
  8.         super.onCreate(savedInstanceState);  
  9.         setContentView(R.layout.main);  
  10.         dp = new DataProvider();  
  11.     }  
  12.       
  13.     //add对应的事件  
  14.     public void add(View view){  
  15.         //执行C语言处理数据  
  16.         int result = dp.add(35);  
  17.         Toast.makeText(this"相加的结果"+ result, 1).show();      
  18.     }  

 

C中回调java方法

声明native 方法:

[java] view plaincopy
 
  1. public class DataProvider{  
  2.     public native void callCcode();  
  3.     public native void callCcode1();  
  4.     public native void callCcode2();  
  5.       
  6.     ///C调用java中的空方法    
  7.     public void helloFromJava(){  
  8.         System.out.println("hello from java ");  
  9.     }  
  10.     //C调用java中的带两个int参数的方法  
  11.     public int Add(int x,int y){  
  12.         System.out.println("相加的结果为"+ (x+y));  
  13.         return x+y;  
  14.     }  
  15.     //C调用java中参数为string的方法  
  16.     public void printString(String s){  
  17.         System.out.println("in java code "+ s);  
  18.     }  
  19. }  

头文件可以用jdk自带的javah进行自动生成,使用javap -s可以获取到方法的签名。

C代码实现回调需要三个步骤:首先要要获取到 某个对象 , 然后获取对象里面的方法  ,最后 调用这个方法  .

[cpp] view plaincopy
 
  1. #include "cn_itcast_ndk4_DataProvider.h"  
  2. #include <string.h>  
  3. #include <android/log.h>  
  4. #define LOG_TAG "logfromc"  
  5. #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)  
  6. #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)  
  7.   
  8. //1.调用java中的无参helloFromJava方法  
  9. JNIEXPORT void JNICALL Java_cn_itcast_ndk4_DataProvider_callCcode  
  10.   (JNIEnv * env , jobject obj){  
  11.     // 获取到DataProvider对象  
  12.     char* classname = "cn/itcast/ndk4/DataProvider";  
  13.     jclass dpclazz = (*env)->FindClass(env,classname);  
  14.     if (dpclazz == 0) {  
  15.             LOGI("not find class!");  
  16.         } else  
  17.             LOGI("find class");  
  18.     //第三个参数 和第四个参数 是方法的签名,第三个参数是方法名  , 第四个参数是根据返回值和参数生成的  
  19.     //获取到DataProvider要调用的方法  
  20.     jmethodID methodID = (*env)->GetMethodID(env,dpclazz,"helloFromJava","()V");  
  21.     if (methodID == 0) {  
  22.             LOGI("not find method!");  
  23.         } else  
  24.             LOGI("find method");  
  25.     //调用这个方法  
  26.     (*env)->CallVoidMethod(env, obj,methodID);  
  27. }  
  28.   
  29. // 2.调用java中的printString方法传递一个字符串  
  30. JNIEXPORT void JNICALL Java_cn_itcast_ndk4_DataProvider_callCcode1  
  31.   (JNIEnv * env, jobject obj){  
  32.     LOGI("in code");  
  33.     // 获取到DataProvider对象  
  34.     char* classname = "cn/itcast/ndk4/DataProvider";  
  35.     jclass dpclazz = (*env)->FindClass(env,classname);  
  36.     if (dpclazz == 0) {  
  37.             LOGI("not find class!");  
  38.         } else  
  39.             LOGI("find class");  
  40.     // 获取到要调用的method  
  41.     jmethodID methodID = (*env)->GetMethodID(env,dpclazz,"printString","(Ljava/lang/String;)V");  
  42.     if (methodID == 0) {  
  43.             LOGI("not find method!");  
  44.         } else  
  45.             LOGI("find method");  
  46.   
  47.     //调用这个方法  
  48.     (*env)->CallVoidMethod(env, obj,methodID,(*env)->NewStringUTF(env,"haha"));  
  49. }  
  50.   
  51. // 3. 调用java中的add方法 , 传递两个参数 jint x,y  
  52. JNIEXPORT void JNICALL Java_cn_itcast_ndk4_DataProvider_callCcode2  
  53.   (JNIEnv * env, jobject obj){  
  54.     char* classname = "cn/itcast/ndk4/DataProvider";  
  55.     jclass dpclazz = (*env)->FindClass(env,classname);  
  56.     jmethodID methodID = (*env)->GetMethodID(env,dpclazz,"Add","(II)I");  
  57.     (*env)->CallIntMethod(env, obj,methodID,3l,4l);  
  58. }  
分享到:
评论

相关推荐

    androidjni编程,java和c层的互相通信传递数据

    - 实现`本地方法`:在C/C++源文件中实现这些函数,使用JNIEnv指针和JNI函数调用来与Java世界交互。 - 编译和链接:使用NDK(Native Development Kit)将C/C++源文件编译为共享库(`.so`文件)。 - 集成到Android...

    Android中JNI实现AES加密源代码

    综上所述,"Android中JNI实现AES加密源代码"涉及的知识点包括Android JNI的使用、AES加密算法的实现、NDK开发环境的配置、C/C++与Java的交互,以及数据安全和性能优化。通过这样的实现,开发者可以在Android应用中...

    Qt for Android 用JNI来使C++和Java互调(目前最新版全网只有这个可用)

    "Qt for Android 用JNI来使C++和Java互调"的主题揭示了如何利用JNI(Java Native Interface)技术在Qt与Android原生系统之间建立桥梁,实现两者的交互。以下将详细介绍这一过程。 首先,Qt for Android是Qt项目的一...

    AndroidJNI 学习 java与c传数据

    这个“AndroidJNI 学习 java与c传数据”主题聚焦于如何通过JNI在Java层和原生C/C++层之间传递数据,这对于优化性能、利用硬件加速或者调用已有的C库是非常有用的。 首先,让我们理解JNI的基本工作原理。JNI为Java...

    androidjni实现本地加解密数据,使用C++语言编写,基于openssl实现 集成RSAAES3DESBASE64MD5

    本项目主要探讨了如何使用C++语言通过JNI(Java Native Interface)与Android应用交互,实现基于OpenSSL库的加解密算法,包括RSA、AES、3DES、BASE64和MD5。以下是关于这些技术的详细解释: 1. **JNI(Java Native ...

    Android使用JNI调用Python so解释器

    使用`JNIEXPORT`和` JNICALL`宏定义函数导出,`JNIEnv *`参数用于在Java和C之间传递数据。 5. **注册JNI方法**:在Java的`native`方法上使用`@Override`注解,并在对应的C/C++头文件中声明这些方法。在`Android.mk`...

    Android下AES加密算法的JNI实现(包含SO文件)

    在Android开发中,有时为了提高性能或利用C/C++库的优势,我们会选择使用JNI(Java Native Interface)来实现部分功能。本资源提供了一个具体的实例,即在Android环境下使用JNI实现AES(Advanced Encryption ...

    Android studio JNI函数以及复杂对象传递

    总的来说,Android Studio的JNI功能为开发者提供了丰富的手段,以C/C++实现性能敏感或跨平台的代码,同时通过JNI调用来与Java层进行交互。理解并熟练掌握JNI的使用,能够帮助开发者充分利用Android系统的底层能力,...

    Android JNI多线程编程回调JAVA函数

    本话题将深入探讨如何在Android中使用JNI进行多线程编程,并实现native方法对Java函数的回调。 1. **JNI基础知识**: - JNI是Java平台的一部分,为Java应用程序提供了与本地代码交互的能力。开发者可以通过JNI在...

    JNI开发Java和C/C++互相传递List集合

    JNI开发Java和C/C++互相传递List集合, 可以参考: Java从C/C++获取List集合对象:...Java传递List集合对象到C/C++ https://blog.csdn.net/niuba123456/article/details/80994168

    jni.rar_Android jni_JAVA串口 JNI_android_android RS232_jni

    本文将详细讲解如何在Android应用中使用JNI封装串口通讯,并通过Java调用来控制串口发送和接收数据。 首先,我们需要理解JNI的概念。JNI是Java平台提供的一种接口,允许Java代码和其他语言写的代码进行交互。在...

    I2CJNI.rar_Android jni_android_android i2c_android i2c通信 JNI_i2c

    综上,"I2CJNI.rar"提供了一个使用Android JNI进行I2C通信的实践案例,对于学习如何在Android平台上通过JNI访问硬件资源,尤其是与I2C设备交互的开发者来说,这是一个宝贵的参考资料。通过研究这个项目,开发者可以...

    aes-jni-java和c互加解密

    本文将详细探讨"android aes-jni Java和C互加解密"这个主题,它涉及到Android平台上的JNI(Java Native Interface)技术以及AES加密在Java和C语言之间的实现。 首先,AES是一种块密码,它对128位的数据进行加密,...

    android jni 中文字符传递demo

    总之,这个"android jni 中文字符传递demo"涵盖了在Android应用中使用JNI处理中文字符的核心技术,这对于那些需要在Java和C/C++之间交换中文数据的开发者来说,是一个非常有价值的参考资料。通过深入学习和实践这个...

    JNI中C和Java参数传递详细例子

    在JNI中,如果要在C/C++和Java之间传递结构体,就需要定义相应的Java类来匹配C/C++中的结构体,并且实现必要的JNI方法来进行转换。 #### 四、实例分析 假设有一个表示硬盘信息的结构体`DiskInfo`: ```c struct ...

    java jni 传递结构体

    文档里描述了如何通过jni方法在java与c++代码之间传递非基本类型数据

    android通过JNI访问硬件LED

    在Android系统中,Java Native Interface (JNI) 是一个关键组件,允许Java代码与其他语言(如C++或C)编写的代码进行交互。本项目聚焦于如何利用JNI来访问硬件资源,特别是控制LED设备。以下是对这个主题的详细阐述...

    Android 串口 JNI 代码

    总之,"Android 串口JNI代码"是指使用JNI技术在Android平台上实现串口通信功能,允许应用程序与外部硬件设备进行数据交换。通过创建本地方法并在C/C++层面处理串口操作,开发者可以绕过Android SDK的限制,实现更...

    JniCallback.zip_Android jni_android_jni android_jni callback_jni

    JNI在很多场景下都非常有用,比如优化性能、使用现有的C/C++库、或者像在这个“JniCallback.zip”文件中所展示的,实现应用层与本地代码之间的回调功能。下面我们将深入探讨这个主题。 1. **JNI基础知识**: JNI是...

    android 在jni中实用openSL ES播放pcm数据

    在Android平台上,JNI(Java Native Interface)允许Java代码与本地C/C++代码进行交互,这样开发者可以利用C/C++的高效性能处理特定任务,比如音频处理。本示例"android在JNI中实用OpenSL ES播放pcm数据"是针对...

Global site tag (gtag.js) - Google Analytics