Android使用JNI實現Java與C之間傳遞資料

來源:互聯網
上載者:User

介紹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語言處理這個相加的邏輯,把相加的結果返回給javapublic native int add(int x ,int y);//把一個java中的字串傳遞給c語言, c 語言處理下字串, 處理完畢返回給java public native String sayHelloInC(String s);//把一個java中int類型的數組傳遞給c語言, c語言裡面把數組的每一個元素的值 都增加5, //然後在把處理完畢的數組,返回給javapublic 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 __cplusplusextern "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    := HelloLOCAL_SRC_FILES := Hello.c #增加 log 函數對應的log 庫  liblog.so  libthread_db.aLOCAL_LDLIBS += -lloginclude $(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!");} elseLOGI("find class");//第三個參數 和第四個參數 是方法的簽名,第三個參數是方法名  , 第四個參數是根據傳回值和參數產生的//擷取到DataProvider要調用的方法jmethodID methodID = (*env)->GetMethodID(env,dpclazz,"helloFromJava","()V");if (methodID == 0) {LOGI("not find method!");} elseLOGI("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!");} elseLOGI("find class");// 擷取到要調用的methodjmethodID methodID = (*env)->GetMethodID(env,dpclazz,"printString","(Ljava/lang/String;)V");if (methodID == 0) {LOGI("not find method!");} elseLOGI("find method");//調用這個方法(*env)->CallVoidMethod(env, obj,methodID,(*env)->NewStringUTF(env,"haha"));}// 3. 調用java中的add方法 , 傳遞兩個參數 jint x,yJNIEXPORT 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);}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.