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

  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就表示的是当前的对象

  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 中进行调试

  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文件

  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代码

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

  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代码实现回调需要三个步骤:首先要要获取到 某个对象 , 然后获取对象里面的方法  ,最后 调用这个方法  .

  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

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

  1. Android使用JNI实现Java与C之间传递数据

    介绍Java如何将数据传递给C和C回调Java的方法. java传递数据给C,在C代码中进行处理数据,处理完数据后返回给java.C的回调是Java传递数据给C,C需要用到Java中的某个方法,就需要 ...

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

    前言: 上一篇文章给大家聊了Intent的用法,如何用Intent启动Activity和隐式Intent,这一篇文章给大家聊聊如何利用Intent在Activity之间进行沟通.   从一个Activ ...

  3. 【Android 复习】 : Activity之间传递数据的几种方式

    在Android开发中,我们通常需要在不同的Activity之间传递数据,下面我们就来总结一下在Activity之间数据传递的几种方式. 1. 使用Intent来传递数据 Intent表示意图,很多时 ...

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

    Fragment 与 Activity之间传递数据有两种方法.一种是使用setArgument,一种是使用接口回调.以下先学习第一种方法. (1)使用setArgument方法: 为了便于理解,我在这 ...

  5. Android之间传递数据包

    在Android中 ,我们知道,两个activity之间通讯要用到Intent类,传递简单数据的方式我们也已经知道了.那么,如何在两个activity之间传递数据包呢,这就要用到我们的Bundle类了 ...

  6. Android基础知识04—Activity活动之间传递数据

    ------活动之间传递数据------ 向下一个活动传递数据: Intent中提供了一系列的putExtra()方法,可以把数据暂存到Intent中,启动另一个活动的时候就可以取出来. 代码: (存 ...

  7. Activity之间传递数据或数据包Bundle,传递对象,对象序列化,对象实现Parcelable接口

    package com.gaojinhua.android.activitymsg; import android.content.Intent; import android.os.Bundle; ...

  8. 在activity之间传递数据

    在activity之间传递数据 一.简介 二.通过intent传递数据 1.在需要传数据的界面调用 intent.putExtra("data1", "我是fry&quo ...

  9. 28、activity之间传递数据&批量传递数据

    import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android ...

随机推荐

  1. Java总结(一):封装——Encapsulation

    官方定义:一种将抽象性函式接口的实作细节部份包装.隐藏起来的方法.封装可以被认为是一个保护屏障,防止该类的代码和数 据被外部类定义的代码随机访问. 大白话定义:通过getter和setter方法访问私 ...

  2. 转: Oracle表空间查询

    1.查询数据库中的表空间名称 1)查询所有表空间 select tablespace_name from dba_tablespaces; select tablespace_name from us ...

  3. 《Head First Servlet JSP》web服务器,容器,servlet的职责

    (一)web服务器,容器,servlet的职责 (二)J2EE服务器与web容器

  4. 【leetcode】Unique Binary Search Trees

    Unique Binary Search Trees Given n, how many structurally unique BST's (binary search trees) that st ...

  5. PHP带重试功能的curl

    2016年1月13日 10:48:10 星期三 /** * @param string $url 访问链接 * @param string $target 需要重试的标准: 返回结果中是否包含$tar ...

  6. c++ 引用和指针

    1.引用 程序把引用和它的初始值绑定在一起,而不是将初始值拷贝给引用.一旦初始化完成,引用将和它的初始值对象一直绑定在一起.因为无法令引用重新绑定到另外一个对象,因此引用必须初始化. int ival ...

  7. 关于TortoiseSVN的一些知识

    TortoiseSVN的一切命令都是相对于它自己来说的 1.Import,导入,指的是导入SVN的代码库,即Repository. 2.Export,导出,指的是将代码从Repository中导出到你 ...

  8. 线条围绕 div 中心转圈 效果

    1. 用到知识: CSS:animate  ,clipe 2.原理: 用clip 属性 将div  切边 ,会出现 切边的动态效果,然后内部的div 遮住外部的div  ,流出一部分 作为边: 就是旋 ...

  9. 【leetcode】Spiral Matrix(middle)

    Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral or ...

  10. (转)Delphi工程文件说明

    1.DPR: Delphi Project文件,包含了Pascal代码.应用系统的工程文件2.PAS: Pascal文件,Pascal单元的源代码,可以是与窗体有关的单元或是独立的单元.3.DFM:D ...