Android JNI中C和JAVA代码之间的互相调用
关于Android studio中使用NDK/JNI环境和入门:http://blog.csdn.net/quan648997767/article/details/64923143
1. C代码回调Java方法的流程
(1) 找到java对应的Class
创建一个char*数组, 然后使用jni.h中提供的FindClass方法获取jclass返回值;
- char* classname = "wjy/geridge/com/testndk/jni/JniUtils";
- jclass dpclazz = (*env)->FindClass(env, classname);
(2) 找到要调用的方法的methodID
使用jni.h中提供的GetMethodID方法, 获取jmethodID, 传入参数 ①JNIEnv指针 ②Class对象 ③ 方法名 ④方法签名, 在这里方法名和方法签名确定一个方法, 方法签名就是方法的返回值 与 参数的唯一标示;
- //参数介绍 : 第二个参数是Class对象, 第三个参数是方法名,第四个参数是方法的签名, 获取到调用的method
- jmethodID methodID = (*env)->GetMethodID(env, dpclazz,"add", "(II)I");
关于JNI方法签名规则
| Java类型 | 类型签名 |
| boolean | Z |
| byte | B |
| char | C |
| short | S |
| int | I |
| long | J |
| float | F |
| double | D |
| 类 | L全限定类名 |
| 数组 | [元素类型签名 |
- jmethodID methodID = (*env)->GetStaticMethodID(env, dpclazz,"add", "(II)I");
可以看到获取静态方法需要调用GetStaticMethodID方法,参数与GetMethodID相同
(3) 在C语言中调用相应方法
- jobject (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, ...);
- jobject (*CallObjectMethodV)(JNIEnv*, jobject, jmethodID, va_list);
- jobject (*CallObjectMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
- jboolean (*CallBooleanMethod)(JNIEnv*, jobject, jmethodID, ...);
- jboolean (*CallBooleanMethodV)(JNIEnv*, jobject, jmethodID, va_list);
- jboolean (*CallBooleanMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
- jbyte (*CallByteMethod)(JNIEnv*, jobject, jmethodID, ...);
- jbyte (*CallByteMethodV)(JNIEnv*, jobject, jmethodID, va_list);
- jbyte (*CallByteMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
- jchar (*CallCharMethod)(JNIEnv*, jobject, jmethodID, ...);
- jchar (*CallCharMethodV)(JNIEnv*, jobject, jmethodID, va_list);
- jchar (*CallCharMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
- jshort (*CallShortMethod)(JNIEnv*, jobject, jmethodID, ...);
- jshort (*CallShortMethodV)(JNIEnv*, jobject, jmethodID, va_list);
- jshort (*CallShortMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
- jint (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);
- jint (*CallIntMethodV)(JNIEnv*, jobject, jmethodID, va_list);
- jint (*CallIntMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
- jlong (*CallLongMethod)(JNIEnv*, jobject, jmethodID, ...);
- jlong (*CallLongMethodV)(JNIEnv*, jobject, jmethodID, va_list);
- jlong (*CallLongMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
- jfloat (*CallFloatMethod)(JNIEnv*, jobject, jmethodID, ...);
- jfloat (*CallFloatMethodV)(JNIEnv*, jobject, jmethodID, va_list);
- jfloat (*CallFloatMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
- jdouble (*CallDoubleMethod)(JNIEnv*, jobject, jmethodID, ...);
- jdouble (*CallDoubleMethodV)(JNIEnv*, jobject, jmethodID, va_list);
- jdouble (*CallDoubleMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
- void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
- void (*CallVoidMethodV)(JNIEnv*, jobject, jmethodID, va_list);
- void (*CallVoidMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
同样的如果是调用静态方法应该使用对应的CallStaticTypeMethod, 其中的Type随着返回值类型不同而改变;
(4) 在C中调用Java的void返回值方法
- jmethodID methodID2 = (*env)->GetStaticMethodID(env, dpclazz,"callNullModth", "()V");
(5) 在C中调用Java带String参数的方法
上面(4)中可以看到String类型的签名是Ljava/lang/String;上面签名规则的例子中也有说到
- //C中调用Java的String参数方法
- jmethodID methodID3 = (*env)->GetStaticMethodID(env, dpclazz,"callStringMethod", "(Ljava/lang/String;)Ljava/lang/String;");
- //添加一个参数
- jstring param = (*env)->NewStringUTF(env, "C中调用Java的String参数方法");
- jstring result = (*env)->CallStaticObjectMethod(env,clazz,methodID3,param);
- //jstring转char*(UTF-8格式)
- char *str = (*env)->GetStringUTFChars(env, result,0);
- LOGI("callStringMethod=%s",str);
上面例子的参数和返回值都是String,GetStringUTFChars方法是在jni.h中声明可以顺便查看下其他相关方法
(6)完整例子代码
- package wjy.geridge.com.testndk.jni;
- import android.util.Log;
- /**
- * Created by zzq on 2017/3/22 0022.
- */
- public class JniUtils {
- public static native int getStringFormc(int x, int y);
- public static native int[] getArray(int[] arr);
- /**
- * 调用带参的Java方法
- * @param x
- * @param y
- * @return
- */
- public static int add(int x,int y){
- return x + y;
- }
- /**
- * 调用JAVA空参数 void返回值的方法
- */
- public static void callNullMethod(){
- Log.e("TAG","C中调用JAVA的void返回值,空参数方法");
- }
- /**
- * 调用JAVA中String参数和返回值的的方法
- */
- public static String callStringMethod(String str){
- return str+"->调用成功";
- }
- }
在Activity中调用:
- package wjy.geridge.com.testndk;
- import android.os.Bundle;
- import android.support.v7.app.AppCompatActivity;
- import android.widget.TextView;
- import wjy.geridge.com.testndk.jni.JniUtils;
- public class MainActivity extends AppCompatActivity {
- private TextView textView;
- static {
- System.loadLibrary("NdkJniDemo");//之前在build.gradle里面设置的so名字,必须一致
- }
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- textView = (TextView) findViewById(R.id.textview);
- textView.setText(JniUtils.getStringFormc(8,9)+"");
- JniUtils.getArray(new int[]{1,2,3,4,15});
- }
- }
C代码:
- #include "string.h"
- #include "wjy_geridge_com_testndk_jni_JniUtils.h"
- #include <android/log.h>
- #define LOG_TAG "System.out"
- #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
- #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
- /*
- * Class: Java_wjy_geridge_com_testndk_jni_JniUtils
- * Method: getStringFormc
- * Signature: ()Ljava/lang/String;
- */
- JNIEXPORT jint JNICALL Java_wjy_geridge_com_testndk_jni_JniUtils_getStringFormc
- (JNIEnv *env, jobject clazz,jint x,jint y){
- char* classname = "wjy/geridge/com/testndk/jni/JniUtils";
- jclass dpclazz = (*env)->FindClass(env, classname);
- //这里实现了互相调用,Java中调用了C的getStringFormc方法传递了x,y参数,这里C又调用了Java的add方法将x,y回传回去求和;
- jmethodID methodID = (*env)->GetStaticMethodID(env, dpclazz,"add", "(II)I");
- LOGI("调用ADD方法的结果count=%d",(*env)->CallStaticIntMethod(env,clazz,methodID,x,y));
- //C中调用Java的空返回值方法
- jmethodID methodID2 = (*env)->GetStaticMethodID(env, dpclazz,"callNullMethod", "()V");
- (*env)->CallStaticVoidMethod(env,clazz,methodID2);
- //C中调用Java的String参数方法
- jmethodID methodID3 = (*env)->GetStaticMethodID(env, dpclazz,"callStringMethod", "(Ljava/lang/String;)Ljava/lang/String;");
- //添加一个参数
- jstring param = (*env)->NewStringUTF(env, "C中调用Java的String参数方法");
- jstring result = (*env)->CallStaticObjectMethod(env,clazz,methodID3,param);
- //jstring转char*
- char *str = (*env)->GetStringUTFChars(env, result,0);
- LOGI("callStringMethod=%s",str);
- return x+y;
- }
- /**
- 打印一个数组
- */
- jintArray Java_wjy_geridge_com_testndk_jni_JniUtils_getArray
- (JNIEnv *env, jobject clazz,jintArray arr){
- int len = (*env)->GetArrayLength(env,arr);
- //在LogCat中打印出arr的大小
- LOGI("the length of array is %d", len);
- //如果长度为0, 返回arr
- if(len == 0){
- return arr;
- }
- //如果长度大于0, 那么获取数组中的每个元素
- jint* p = (*env)->GetIntArrayElements(env, arr, 0);
- //打印出数组中每个元素的值
- for(int i = 0; i < len; i ++)
- {
- LOGI("arr[%d] = %d", i, *(p + i));
- }
- return arr;
- }
运行结果:
上面代码写了一个打印数组的例子,我这里为了方便都是用的静态方法。
- #include <android/log.h>
- #define LOG_TAG "System.out"
- #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
- #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
- android {
- defaultConfig {
- ndk {
- moduleName "NdkJniDemo" //生成的so名字
- abiFilters "armeabi", "armeabi-v7a", "x86" //输出指定三种abi体系结构下的so库,目前可有可无。
- ldLibs "log", "z", "m"
- }
- }
Android JNI中C和JAVA代码之间的互相调用的更多相关文章
- Android应用中如何保护JAVA代码
Java Classes字节码的反编译太容易了,有很多功能强大的反编译利器可以轻松的将Java字节码 反转为源代码,但是android中普通.apk文件可以轻松的被反编译为Java源代码吗? 答案是当 ...
- Android Studio中批量注释 Java代码
•ctrl+/ 选中需要注释的多行代码,然后按 ctrl + / 实现多行快速注释: 再次按下 ctrl + / 取消注释. •ctrl+shift+/ 选中一行或几行代码,按 ctrl + shif ...
- Android JNI中的数据传递
1.JNI 基本类型 当 Java 代码与本地代码 C/C++ 代码相互调用时,肯定会有参数的传递.两者属于不同的语言,数据类型有差别,此时,JNI 要保证两种语言之间的数据类型和数据空间大小的匹配. ...
- ZT ANDROID jni 中的事件回调机制JNIenv的使用 2012-09-10 12:53:01
ANDROID jni 中的事件回调机制JNIenv的使用 2012-09-10 12:53:01 分类: 嵌入式 android framework 里java调用native,使用JNI机制,ja ...
- Jni中C++和Java的参数传递 参数对照
Jni中C++和Java的参数传递 如何使用JNI的一些基本方法和过程在网上多如牛毛,如果你对Jni不甚了解,不知道Jni是做什么的,如何建立一个基本的jni程序,或许可以参考下面下面这些文章:利用V ...
- Jni中C++和Java的参数传递
Jni中C++和Java的参数传递 如何使用JNI的一些基本方法和过程在网上多如牛毛,如果你对Jni不甚了解,不知道Jni是做什么的,如何建立一个基本的jni程序,或许可以参考下面下面这些文章:利用V ...
- Jni中C++和Java的参数传递(转)
如何使用JNI的一些基本方法和过程在网上多如牛毛,如果你对Jni不甚了解,不知道Jni是做什么的,如何建立一个基本的jni程序,或许可以参考下面下面这些文章:利用VC++6.0实现JNI的最简单的例子 ...
- android开发中,在java中怎样使用c提供过来char*
这个char*假设是一般的字符串的话,作为string传回去就能够了.假设是含有'\0'的buffer,最好作为bytearray传出,由于能够制定copy的length.假设copy到string, ...
- [Android Tips] 30.如何在 Android Studio 中一次性格式化所有代码
在目录上面右击,有 Reformat Code Ctrl + Alt + L 参考 如何在IntelliJ IDEA或Android Studio中一次性格式化所有代码?
随机推荐
- 【Ray Tracing in One Weekend 超详解】 光线追踪1-7 Dielectric 半径为负,实心球体镂空技巧
今天讲这本书最后一种材质 Preface 水,玻璃和钻石等透明材料是电介质.当光线照射它们时,它会分裂成反射光线和折射(透射)光线. 处理方案:在反射或折射之间随机选择并且每次交互仅产生一条散射光线 ...
- Django模版语言inclusion_tag的用法。
inclusion_tag.它多用于一个HTML片段的.例如我写的一个BBS项目中. 一个博主的主页面的左侧栏和查看博主某篇文章的页面的左栅栏的一样的.为了不用重复写同样的代码.且提高页面的扩 ...
- BZOJ.2142.礼物(扩展Lucas)
题目链接 答案就是C(n,m1) * C(n-m1,m2) * C(n-m1-m2,m3)...(mod p) 使用扩展Lucas求解. 一个很简单的优化就是把pi,pi^ki次方存下来,因为每次分解 ...
- PHP 合理配置实现文件上传及保存文件到数据库
合理配置 php.ini 如何配置php.ini实现PHP文件上传功能.其中涉及到php.ini配置文件中的upload_tmp_dir.upload_max_filesize.post_max_si ...
- hdu 4451 37届金华赛区 J题
题意:给出衣服裤子鞋子的数目,有一些衣服和裤子,裤子和鞋子不能搭配,求最终的搭配方案总数 wa点很多,我写wa了很多次,代码能力需要进一步提升 #include<cstdio> #incl ...
- AIM Tech Round 3 (Div. 1) B. Recover the String 构造
B. Recover the String 题目连接: http://www.codeforces.com/contest/708/problem/B Description For each str ...
- Springboot 线程池配置
最近的项目里要手动维护线程池,然后看到一起开发的小伙伴直接用Java了,我坚信Springboot不可能没这功能,于是查了些资料,果然有,这里给一下. 首先我们都知道@Async标签能让方法异步执行, ...
- nginx+uwsgi+flask 服务器配置
注:每个机器,软件版本可能不一样,虽然网上有很多类似的帖子,但是我在搭建的时候遇到了不少的坑,此文仅供参考. 请求流程: 1.安装uwsgi uwsgi是一个应用服务器,非静态文件的网络请求就必须通过 ...
- ConcurrentHashMap之实现细节(转)
ConcurrentHashMap是Java 5中支持高并发.高吞吐量的线程安全HashMap实现.在这之前我对ConcurrentHashMap只有一些肤浅的理解,仅知道它采用了多个锁,大概也足够了 ...
- 「GIT SourceTree冲突」解决方案
现在程序猿标配GIT作为代码管理,但是从SVN到GIT学习中,其中GIT的冲突是一个难点,常常会导致Push不上去,Pull不下来,很尴尬的地步,还不知道自己写的代码被覆盖没,废话不多说,直接上干货! ...