读书人

Android运用JNI实现Java与C之间传递数

发布时间: 2013-02-19 11:11:41 作者: rapoo

Android使用JNI实现Java与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??? := 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 <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);?
??? }?
Android相关内容:

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

读书人网 >Android

热点推荐