zoukankan      html  css  js  c++  java
  • 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]; ""  
              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);  
        }  
  • 相关阅读:
    把联系人从一张卡转移到另一张卡或者从一个手机转移到另一个手机
    Echarts画折线图
    Echarts画条形图
    Echarts画饼状图
    《计算机网络》读后感
    Vue.js项目无法启动:sh: 1: vue-cli-service: not found
    《Redis入门指南(第 2 版)》读后感
    翻译:《实用的Python编程》InstructorNotes
    翻译:《实用的Python编程》TheEnd
    翻译:《实用的Python编程》09_03_Distribution
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/6155043.html
Copyright © 2011-2022 走看看