c 反射调用java_JNI C反射调用java方法

④通过对象调用方法,可以调用空参数方法,也可以调用有参数方法,并且将参数通过调用的方法传入(void (CallVoidMethod)(JNIEnv, jobject, jmethodID, ...);)

首先,也是按照前面的步骤新建一个 import C++ 工程,新建ccalljava.c 和一个JNI.java文件(别忘了修改CMakeLists.txt对应C方法的名字和路径)

84bf45066dda218fc7d783f52ab0ec68.png

JNI.java中编写本地方法:

//C调用java空方法

public native voidcallbackmethod();//C调用java中的带两个int参数的方法

public native voidcallbackIntmethod();//C调用java中参数为string的方法

public native voidcallbackStringmethod();//C调用java中静态方法

public native void callStaticmethod();

并且编写被C反调的java方法:

//C调用java空方法

public voidhelloFromJava(){

Toast.makeText(context,"C调用了java的空方法",Toast.LENGTH_SHORT ).show();}//C调用java中的带两个int参数的方法

public int add(int x,inty) {return x+y;}//C调用java中参数为string的方法

public voidprintString(String s){

Toast.makeText(context, s, Toast.LENGTH_SHORT).show();}//C调用java中静态方法

public static voidstaticmethod(String s){

Log.w("毛麒添",s+",我是被C调用的静态方法");}

下面来编写ccalljava.c中的C方法

/**C函数反射调用java中的空方法*/JNIEXPORTvoid JNICALLJava_com_mao_ccalljava_JNI_callbackmethod(JNIEnv *env, jobject object) {

jclass jclazz= (*env)->FindClass(env, "com/mao/ccalljava/JNI");

jmethodID methodID= (*env)->GetMethodID(env, jclazz, "helloFromJava", "()V");

(*env)->CallVoidMethod(env,object,methodID);}/**

调用java中Int方法*/JNIEXPORTvoid JNICALLJava_com_mao_ccalljava_JNI_callbackIntmethod(JNIEnv *env, jobject object) {

jclass clzz=(*env)->FindClass(env,"com/mao/ccalljava/JNI");

jmethodID methodID=(*env)->GetMethodID(env,clzz,"add","(II)I");int result=(*env)->CallIntMethod(env,object,methodID,3,4);//logcat 打印相加返回的结果

LOGD("RESLUT = %d",result);

}/**

调用java中String方法*/JNIEXPORTvoid JNICALLJava_com_mao_ccalljava_JNI_callbackStringmethod(JNIEnv *env, jobject object) {//先获取字节码对象 jclass (*FindClass)(JNIEnv*, const char*);

jclass clzz=(*env)->FindClass(env,"com/mao/ccalljava/JNI");//获取method对象 jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);

jmethodID methodID=(*env)->GetMethodID(env,clzz,"printString","(Ljava/lang/String;)V");//将要传递的字符串先转换成jstring类型 ,然后在传递给java方法 int result=(*env)->NewStringUTF(env,"hello form C/C++ "); (*env)->CallVoidMethod(env,object,methodID,result);

}/**

调用Java中的静态方*/JNIEXPORTvoid JNICALLJava_com_mao_ccalljava_JNI_callStaticmethod(JNIEnv *env, jobject instance) {

jclass clzz=(*env)->FindClass(env,"com/mao/ccalljava/JNI");

jmethodID methodID=(*env)->GetStaticMethodID(env,clzz,"staticmethod","(Ljava/lang/String;)V");

jstring str= (*env)->NewStringUTF(env, "C调用java");

(*env)->CallStaticVoidMethod(env,clzz,methodID,str);

}

通过字节码对象找到方法对象,该方法中的第四个参数是方法签名

jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);

获取方法签名的方法是进入工程目的 ..../build/classes/debug 进入控制台,

输入命令 javap -s 要获取方法的路径(例如本例 javap -s com.mao.ccalljava.JNI)

b551d0db488edb744c7f0fd752352b35.png

865084fd54cb5147f745b1ea01933aba.png

上面步骤二中提到的没有生命周期的解决方法:

报空指针,主要就是没上下文环境,反射调用的方法是new出来的,也会没有生命周期.这时候就可以将本地方法和调用的方法都放在同一个类中,没有上下文环境就在创建方法的时候在构造方法中接收一个。

privateContext context;publicJNI(Context context){this.context=context;

}

最后,别忘了添加在JNI.java中添加动态链接库文件(布局和MianActiivty中逻辑比较简单,这里

static{

System.loadLibrary("ccalljava");

}

在gradle 配置一些处理器架构

externalNativeBuild {

cmake {

cppFlags""

//Clang是一个C语言、Objective-C、C++语言的轻量级编译器。

arguments "-DANDROID_TOOLCHAIN=clang"

//生成.so库的目标平台

abiFilters "armeabi-v7a" , "armeabi" ,"x86"}

}

接下来在工程编译通过后可以该目录下找到不同处理器架构的动态链接库文件

9f3c0cc22255d021f75f5f04b42dcc02.png

最后,上几张运行成功的截图:

495074bdfdc9a23d5a6cd25f7253f2f5.png

0a7b1cd991875b8932b8d7953565bfa7.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值