Android使用JNI实现Java与C之间传递数据
16lz
2022-01-17
Android使用JNI实现Java与C之间传递数据
介绍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 方法:
[java] view plain copy print ? 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就表示的是当前的对象
[cpp] view plain copy print ? /* 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 __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 中进行调试
编写Android.mk文件
[cpp] view plain copy print ? 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代码
[java] view plain copy print ? 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 方法:
[java] view plain copy print ? 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 plain copy print ? #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 调用系统文件管理器
- 混合开发之ReactNative调用Android原生方法
- Android投屏电脑反向控制软件QtScrcpy使用方法
- SQLite在android 的一些用法与Cursor的体会
- Android入门篇二:使用意图在Activity之间传递数据
- QtAndroid详解(5):JNI调用Android系统功能(2)
- 《Android移动应用基础教程》(Android(安卓)Studio)(第二版)黑马教程
- 浅谈Java中Collections.sort对List排序的两种方法
- Python list sort方法的具体使用