Android使用JNI实现Java与C之间传递数据(转)

介绍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. //把一个java中的字符串传递给c语言, c 语言处理下字符串, 处理完毕返回给java
  5. public native String sayHelloInC(String s);
  6. //把一个java中int类型的数组传递给c语言, c语言里面把数组的每一个元素的值 都增加5,
  7. //然后在把处理完毕的数组,返回给java
  8. public native int[] intMethod(int[] iNum);
  9. }

以上方法要在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. #ifndef _Included_cn_itcast_ndk3_DataProvider
  5. #define _Included_cn_itcast_ndk3_DataProvider
  6. #ifdef __cplusplus
  7. extern "C" {
  8. #endif
  9. /*
  10. * Class:     cn_itcast_ndk3_DataProvider
  11. * Method:    add
  12. * Signature: (II)I
  13. */
  14. JNIEXPORT jint JNICALL Java_cn_itcast_ndk3_DataProvider_add
  15. (JNIEnv *, jobject, jint, jint);
  16. /*
  17. * Class:     cn_itcast_ndk3_DataProvider
  18. * Method:    sayHelloInC
  19. * Signature: (Ljava/lang/String;)Ljava/lang/String;
  20. */
  21. JNIEXPORT jstring JNICALL Java_cn_itcast_ndk3_DataProvider_sayHelloInC
  22. (JNIEnv *, jobject, jstring);
  23. /*
  24. * Class:     cn_itcast_ndk3_DataProvider
  25. * Method:    intMethod
  26. * Signature: ([I)[I
  27. */
  28. JNIEXPORT jintArray JNICALL Java_cn_itcast_ndk3_DataProvider_intMethod
  29. (JNIEnv *, jobject, jintArray);
  30. #ifdef __cplusplus
  31. }
  32. #endif
  33. #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. // java中的jstring, 转化为c的一个字符数组
  12. char*   Jstring2CStr(JNIEnv*   env,   jstring   jstr)
  13. {
  14. char*   rtn   =   NULL;
  15. jclass   clsstring   =   (*env)->FindClass(env,"java/lang/String");
  16. jstring   strencode   =   (*env)->NewStringUTF(env,"GB2312");
  17. jmethodID   mid   =   (*env)->GetMethodID(env,clsstring,   "getBytes",   "(Ljava/lang/String;)[B");
  18. jbyteArray   barr=   (jbyteArray)(*env)->CallObjectMethod(env,jstr,mid,strencode); // String .getByte("GB2312");
  19. jsize   alen   =   (*env)->GetArrayLength(env,barr);
  20. jbyte*   ba   =   (*env)->GetByteArrayElements(env,barr,JNI_FALSE);
  21. if(alen   >   0)
  22. {
  23. rtn   =   (char*)malloc(alen+1);         //new   char[alen+1]; "\0"
  24. memcpy(rtn,ba,alen);
  25. rtn[alen]=0;
  26. }
  27. (*env)->ReleaseByteArrayElements(env,barr,ba,0);  //释放内存
  28. return rtn;
  29. }
  30. //处理整形相加
  31. JNIEXPORT jint JNICALL Java_cn_itcast_ndk3_DataProvider_add
  32. (JNIEnv * env, jobject obj, jint x, jint y){
  33. //打印 java 传递过来的 jstring ;
  34. LOGI("log from c code ");
  35. LOGI("x= %ld",x);
  36. LOGD("y= %ld",y);
  37. return x+y;
  38. }
  39. //处理字符串追加
  40. JNIEXPORT jstring JNICALL Java_cn_itcast_ndk3_DataProvider_sayHelloInC
  41. (JNIEnv * env, jobject obj, jstring str){
  42. char* p =  Jstring2CStr(env,str);
  43. LOGI("%s",p);
  44. char* newstr = "append string";
  45. //strcat(dest, sorce) 把sorce字符串添加到dest字符串的后面
  46. LOGI("END");
  47. return (*env)->NewStringUTF(env, strcat(p,newstr));
  48. }
  49. //处理数组中的每一个元素
  50. JNIEXPORT jintArray JNICALL Java_cn_itcast_ndk3_DataProvider_intMethod
  51. (JNIEnv * env, jobject obj, jintArray arr){
  52. // 1.获取到 arr的大小
  53. int len = (*env)->GetArrayLength(env, arr);
  54. LOGI("len=%d", len);
  55. if(len==0){
  56. return arr;
  57. }
  58. //取出数组中第一个元素的内存地址
  59. jint* p = (*env)-> GetIntArrayElements(env,arr,0);
  60. int i=0;
  61. for(;i<len;i++){
  62. LOGI("len=%ld", *(p+i));//取出的每个元素
  63. *(p+i) += 5; //取出的每个元素加五
  64. }
  65. return arr;
  66. }

编写Android.mk文件

[cpp] view plaincopy

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

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

[java] view plaincopy

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

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. ///C调用java中的空方法
  6. public void helloFromJava(){
  7. System.out.println("hello from java ");
  8. }
  9. //C调用java中的带两个int参数的方法
  10. public int Add(int x,int y){
  11. System.out.println("相加的结果为"+ (x+y));
  12. return x+y;
  13. }
  14. //C调用java中参数为string的方法
  15. public void printString(String s){
  16. System.out.println("in java code "+ s);
  17. }
  18. }

头文件可以用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. //1.调用java中的无参helloFromJava方法
  8. JNIEXPORT void JNICALL Java_cn_itcast_ndk4_DataProvider_callCcode
  9. (JNIEnv * env , jobject obj){
  10. // 获取到DataProvider对象
  11. char* classname = "cn/itcast/ndk4/DataProvider";
  12. jclass dpclazz = (*env)->FindClass(env,classname);
  13. if (dpclazz == 0) {
  14. LOGI("not find class!");
  15. } else
  16. LOGI("find class");
  17. //第三个参数 和第四个参数 是方法的签名,第三个参数是方法名  , 第四个参数是根据返回值和参数生成的
  18. //获取到DataProvider要调用的方法
  19. jmethodID methodID = (*env)->GetMethodID(env,dpclazz,"helloFromJava","()V");
  20. if (methodID == 0) {
  21. LOGI("not find method!");
  22. } else
  23. LOGI("find method");
  24. //调用这个方法
  25. (*env)->CallVoidMethod(env, obj,methodID);
  26. }
  27. // 2.调用java中的printString方法传递一个字符串
  28. JNIEXPORT void JNICALL Java_cn_itcast_ndk4_DataProvider_callCcode1
  29. (JNIEnv * env, jobject obj){
  30. LOGI("in code");
  31. // 获取到DataProvider对象
  32. char* classname = "cn/itcast/ndk4/DataProvider";
  33. jclass dpclazz = (*env)->FindClass(env,classname);
  34. if (dpclazz == 0) {
  35. LOGI("not find class!");
  36. } else
  37. LOGI("find class");
  38. // 获取到要调用的method
  39. jmethodID methodID = (*env)->GetMethodID(env,dpclazz,"printString","(Ljava/lang/String;)V");
  40. if (methodID == 0) {
  41. LOGI("not find method!");
  42. } else
  43. LOGI("find method");
  44. //调用这个方法
  45. (*env)->CallVoidMethod(env, obj,methodID,(*env)->NewStringUTF(env,"haha"));
  46. }
  47. // 3. 调用java中的add方法 , 传递两个参数 jint x,y
  48. JNIEXPORT void JNICALL Java_cn_itcast_ndk4_DataProvider_callCcode2
  49. (JNIEnv * env, jobject obj){
  50. char* classname = "cn/itcast/ndk4/DataProvider";
  51. jclass dpclazz = (*env)->FindClass(env,classname);
  52. jmethodID methodID = (*env)->GetMethodID(env,dpclazz,"Add","(II)I");
  53. (*env)->CallIntMethod(env, obj,methodID,3l,4l);
  54. }

转自:http://blog.csdn.net/furongkang/article/details/6857610

时间: 2024-11-08 10:10:47

Android使用JNI实现Java与C之间传递数据(转)的相关文章

Android 学习之路 1:Activity之间传递数据的四种方式

传递数据 新建 Activity 在项目中右键,选择 New,继续选择中下方的 Activity,最后是 Blank Activity. 此时 Android Studio 会为我们自动添加一个对应的布局文件,为布局文件中的 TextView 添加 ID,以便后续使用. 用Intent 发送数据 在主布局文件中新建一个 Button 控件,并在主类中定义它,然后为它设置 Click 的监听事件. Button button; @Override protected void onCreate(B

【Android基础】利用Intent在Activity之间传递数据

前言: 上一篇文章给大家聊了Intent的使用方法.怎样用Intent启动Activity和隐式Intent.这一篇文章给大家聊聊怎样利用Intent在Activity之间进行沟通. 从一个Activity获取返回结果: 启动一个Activity不不过startActivity(Intent intent)一种方法.你也能够通过startActivityForResult()启动一个Activity而且在它退出的时候收到一个返回结果. 比方.你能够调用系统相机在你的应用中,拍了一张照片,然后返回

Android 笔记-Fragment 与 Activity之间传递数据

Fragment 与 Activity之间传递数据有两种方法,一种是使用setArgument,一种是使用接口回调.下面先学习第一种方法. (1)使用setArgument方法: 为了便于理解,我在这里打个比喻:假如Activity是皇帝,它设立了三个部门(如三省六部),分别是Fragment1,Fragment2和Fragemnt3: 现在他现在要吩咐部门Fragment1去做一些事情,比如说:领兵攻打岛国!!好,它肯定不自己跑去告诉该部门的. 一般来说,会有个宰相或者太监总管来负责皇帝口谕是

Android笔记Fragment与Activity之间传递数据

Fragment 与 Activity之间传递数据有两种方法,一种是使用setArgument,一种是使用接口回调.下面先学习第一种方法. (1)使用setArgument方法: 为了便于理解,我在这里打个比喻:假如Activity是皇帝,它设立了三个部门(如三省六部),分别是Fragment1,Fragment2和Fragemnt3: 现在他现在要吩咐部门Fragment1去做一些事情,比如说:领兵攻打岛国!!好,它肯定不自己跑去告诉该部门的. 一般来说,会有个宰相或者太监总管来负责皇帝口谕是

Android多线程研究(5)——线程之间共享数据

一.如果是每个线程都执行相同的代码,则可以使用同一个Runnable来实现共享 public class MultiThreadShareData { public static void main(String[] args) { new Thread(new ShareData()).start(); new Thread(new ShareData()).start(); } static class ShareData implements Runnable{ private int j

mvc如何使用JavaScript在view和controller之间传递数据

在一般的BS项目开发中,我们经常需要在前台和后台之间传递数据,mvc架构中,也需要在view和controller之间传递数据,那么我们应该如何实现呢? view想controller传递数据:view中代码 <li>@Html.ViewComponent().WfSaveLink(Model).Id("saveToLink").OnBeforeDo("externalData")</li> <scriptlanguage="

在ViewController之间传递数据的方法【iOS】

在ViewController之间传递数据的方法有不少,博主这里总结两种最常用的方法给大家: 我们假设有 视图控制器A 和 视图控制器B,其中我们设视图控制器B 是由 视图控制器A通过Navigation controller Push过去的,也就是说视图控制器B是视图控制器A的子视图控制器. 下面我们就分别通过 A->B 和 B->A传递数据说明两种在视图控制器之间传递数据的方法. 1.由视图控制器A传递数据给视图控制器B 这里,我的视图控制器A是 ViewController 视图控制器B

【MVC架构】——怎样利用Json在View和Controller之间传递数据

在MVC架构中,尽管非常多东西和三层非常相似,可是也有非常大的差别.就比方传递数据.在三层架构中,传递数据就仅仅要一层返回,另外一层用同样类型的变量来接收即可了.在MVC中,事实上原理是一样的,Controller中的方法返回Json字符串.然后View来接收.或者反过来,不同的就是这之间须要一个序列化和反序列化的过程. 本文就简介利用Json在View和Controller之间传递数据的一个方面,大致从双方面介绍,一是什么是Json,二是怎样实现. 什么是Json 一.概念 百度百科说:JSO

Activity之间传递数据的方式及常见问题总结

转载请注明:大飞 http://blog.csdn.net/rflyee/article/details/47431633 Activity之间传递数据一般通过以下几种方式实现: 1. 通过intent传递数据 2. 通过Application 3. 使用单例 4. 静态成员变量.(可以考虑 WeakReferences) 5. 持久化(sqlite.share preference.file等) 一.通过intent传递数据 (1)直接传递,intent.putExtra(key, value