介紹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就表示的是當前的物件

#include <jni.h>
#ifndef _Included_cn_itcast_ndk3_DataProvider

#define _Included_cn_itcast_ndk3_DataProvider
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jint JNICALL Java_cn_itcast_ndk3_DataProvider_add
(JNIEnv *, jobject, jint, jint);
JNIEXPORT jstring JNICALL Java_cn_itcast_ndk3_DataProvider_sayHelloInC
(JNIEnv *, jobject, jstring);
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代碼實現回檔需要三個步驟:首先要要獲取到 某個物件 , 然後獲取物件裡面的方法 ,最後 調用這個方法 .


 

#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);
}

 

from:http://blog.sina.com.cn/s/blog_40d608bb0100v6hb.html

 

arrow
arrow
    全站熱搜

    戮克 發表在 痞客邦 留言(0) 人氣()