歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Android使用JNI實現Java與C之間傳遞數據

Android使用JNI實現Java與C之間傳遞數據

日期:2017/3/1 11:13:16   编辑:Linux編程
介紹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)
Copyright © Linux教程網 All Rights Reserved