`
star65225692
  • 浏览: 268344 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类

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

    #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); 
    } 
Android相关内容:

分享到:
评论

相关推荐

    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

    java jni 传递结构体

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

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

    android开发之jni开发,java层native层之间的相互调用,方便广大学者工作者学习参考

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

    JNI中C和Java参数传递详细例子,各种数据类型,基本类型,数据,结构体,DEMO,非常适合初学者,一看就明,详细例子

    android jni 中文字符传递demo

    android jni 中文字符传递demo,实现了C语言与java端之间互相传递汉字的功能。例程开发环境为eclipse。详细说明,见相关博客。

    android jni 传递对象的demo

    android jni 传递对象的demo,展示了如何在java与C之间传递对象。详细介绍见相关博客。

    ocos2d-x 通过JNI实现c/c++和Android的java层函数互调

    cocos2d-x 通过JNI实现c/c++和Android的java层函数互调, 本文主要实现两个功能: (1)通过Android sdk的API得到应用程序的包名(PackageName),然后传递给c++层函数。 (2)通过c++函数调用Android的java层函数,显示一...

    Jni中C++和Java的参数传递

    Jni中C++和Java的参数传递如何使用JNI的一些基本方法和过程在网上多如牛毛,如果你对Jni不甚了解,不知道Jni是做什么的,如何建立一个基本的jni程序,或许可以参考下面下面这些文章:利用VC++6.0实现JNI的最简单的...

    Android APP 用interface 接口的形式对jni进行回调,实例测试

    Android APP 用interface 接口的形式对jni进行回调,实例测试

    android下用java调用c/c++实现jni

    上篇文章中已经介绍了,关于NDK开发环境的搭建,这里不做赘述。这篇文章主要是通过一个例子来说明如何通过eclispe自动生成.h头文件,适合初学者,详见http://write.blog.csdn.net/postedit/42144847

    jni数据类型转换

    jni数据类型转换例程 1. java向native传递常用基本数据类型 和字符串类型 2. java向native传递数组类型 3. java向native传递自定义java对象 4. java向native传递任意java对象(以向native传递ArrayList为例) 5....

    JNI完全技术手册 带完整书签

    Chap8:如何将java传递过来的jbyteArray转换成C/C++中的BYTE数组... 47 Chap5:使用JNI技术实现java程序调用第三方dll(c/c++)文件的功能... 47 Chap9:如何编写jni方法(转载)... 55 1、实例一:在jni中调用标准c中...

    CSTR&Handle Java 客户端.rar

    文章介绍了Android NDK开发的简单概念、常见错误及处理和从第一个Hello World开始实际做一个简单的JNI开发示例,相信看完之后,大家对NDK开发有了一个概念上的认识了,那么接下来我们需要再深入一下NDK的开发,我们...

    android ndk开发数据结构传递示例

    一份可供学习的ndk开发示例 使用ndk r4b开发 主要示范如何从android java端传递数据结构以及从ndk接收数据结构 有相应教程: http://blog.csdn.net/hdw_191/archive/2011/02/16/6188852.aspx

    Android中的JNI数组操作教程

    对于基本数据类型数组,JNI 都有和 Java 相对应的结构,在使用起来和基本数据类型的使用类似。 在 Android JNI 基础知识篇提到了 Java 数组类型对应的 JNI 数组类型。比如,Java int 数组对应了 jintArray,boolean ...

    android_JNI编程_一些技巧

    本篇将介绍在JNI编程中如何传递参数和返回值。...首先要强调的是,native方法不但可以传递Java的基本类型做参数,还可以传递更复杂的类型,比如String,数组,甚至自定义的类。这一切都可以在jni.h中找到答案

    Cocos2d-x与Android交互(c++与java互调),与IOS交互(c++与objective c混编)

    Cocos2d-x与Android交互(c++与java互调),与IOS交互(c++与objective c混编) 具体的代码请下载这个文件,里面有更详细的jni使用方法,包括传递基本数据类型,返回基本数据类型的值,及类型的转换。

    Android代码-Android

    Android 本目录下的代码都是来自于我的...JniCallback 演示了如何从Native线程回调Java的函数,相关博文:Android开发实践:JNI层线程回调Java函数示例 JniBuffer 演示了各种从Java端到Native层的Buffer传递方法,相

    jni 调用对象以及数组

    本文比较详细 使用jni技术,java里的对象传到c/c++文件里,并且在c/c++里修改后,传到java,以及怎样使用java的listerner,怎么传输数组到c/c++里

    JAVA上百实例源码以及开源项目源代码

     Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...

Global site tag (gtag.js) - Google Analytics