阅读更多

 介绍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  
    /* 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  
    //导入日志头文件 
    #include  
    //修改日志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            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  
    #include  
    #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相关内容:

  • 添加中减去 textview 中的数字
  • 应作出的 densitys 和大小不同的资源呢?
  • 如何将数据保存到坚持更新之间的 android 应用程序在内部存储?
  • 您可以绘制和使用 Android 的 xml 中的编辑视图吗?
  • Android中application的theme不生效的解决方法

更多相关文章

  1. 浅谈Java中Collections.sort对List排序的两种方法
  2. Python list sort方法的具体使用
  3. python list.sort()根据多个关键字排序的方法实现
  4. android上一些方法的区别和用法的注意事项
  5. android实现字体闪烁动画的方法
  6. Android(安卓)Wifi模块分析(三)
  7. Android中dispatchDraw分析
  8. Android四大基本组件介绍与生命周期
  9. Android(安卓)MediaPlayer 常用方法介绍

随机推荐

  1. android基本架构
  2. 基于蓝牙socket开发Android蓝牙通信
  3. Android实现全屏显示的方法
  4. Android练习
  5. android-浅谈
  6. android google地图定位开发,且可以自由移
  7. android常见的研究方向
  8. android JNI (二) 第一个 android工程
  9. layout_gravity和gravity的区别
  10. Android中背景选择器