JNI C反射调用java方法

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

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

JNI C反射调用java方法

JNI.java中编写本地方法:

//C调用java空方法
public native void callbackmethod();
//C调用java中的带两个int参数的方法
public native void callbackIntmethod();
//C调用java中参数为string的方法
public native void callbackStringmethod();
//C调用java中静态方法
public native void callStaticmethod();

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

//C调用java空方法
public void helloFromJava(){
Toast.makeText(context, "C调用了java的空方法",Toast.LENGTH_SHORT ).show();}
//C调用java中的带两个int参数的方法
public int add(int x,int y) {
return x+y;}
//C调用java中参数为string的方法
public void printString(String s){
Toast.makeText(context, s, Toast.LENGTH_SHORT).show();}
//C调用java中静态方法
public static void staticmethod(String s){
Log.w("毛麒添",s+",我是被C调用的静态方法");}

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

/**C函数反射调用java中的空方法 */
JNIEXPORT void 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方法
 */
JNIEXPORT void 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方法
*/
JNIEXPORT void 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中的静态方
 */
JNIEXPORT void 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)

JNI C反射调用java方法

JNI C反射调用java方法

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

private Context context;
public JNI(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"
        }
}

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

JNI C反射调用java方法

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

JNI C反射调用java方法

例子源码地址:https://github.com/maoqitian/CcallJava

Original: https://www.cnblogs.com/zhujiabin/p/10606029.html
Author: 星辰之力
Title: JNI C反射调用java方法

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/538840/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Redis学习笔记

    Redis 参考博客https://www.cnblogs.com/beiluowuzheng/https://www.cnblogs.com/hunternet/如有侵权,请联系…

    Java 2023年6月5日
    067
  • Spring Cloud Gateway配置自定义异常返回

    0. 前言 最近搞微服务的全家桶,用到的Spring Cloud Gateway 这个组件。需要对这个网关抛出的异常进行自定义。网关的异常处理跟单体SpringBoot的全局异常处…

    Java 2023年5月30日
    056
  • RocketMQ的push消费方式实现的太聪明了

    大家好,我是三友,我又来了~~ 最近仍然畅游在RocketMQ的源码中,这几天刚好翻到了消费者的源码,发现RocketMQ的对于push消费方式的实现简直太聪明了,所以趁着我脑子里…

    Java 2023年6月16日
    0114
  • java学习之EL和JSTL

    EL和JSTL都是JSP的内容的拓展,都是开发的一些东西,稍微学习记录一下,避免以后忘记 概念:Expression language 表达式语言作用:替换和简化JSP页面中的ja…

    Java 2023年6月13日
    079
  • springboot有两个主启动类时,maven打包(可执行包)会报错,需指定启动主类

    我本地写了一个rabbitmq fanout模式的demo。consumer启动类和producer启动类都放到了一个springboot程序里。本地调试通过。 突然有个疑问,sp…

    Java 2023年6月15日
    081
  • 从0到1写一款自动为Markdown标题添加序号的Jetbrains插件

    1. markdown-index 最近做了一个Jetbrains的插件,叫 markdown-index,它的作用是为Markdown文档的标题自动添加序号,效果如下: 目前已经…

    Java 2023年6月7日
    093
  • Java高并发教程:详解NIO Buffer类及其属性

    Java高并发教程:详解NIO Buffer类及其属性 NIO Buffer NIO的Buffer(缓存区) 本质上是一个内存块,既可以写入数据,也可以从中读取数据。NIO的Buf…

    Java 2023年5月29日
    088
  • mybatis-plus快速入门使用

    目前正在维护的公司的一个项目是一个ssm架构的java项目,dao层的接口有大量数据库查询的方法,一个条件变化就要对应一个方法,再加上一些通用的curd方法,对应一张表的dao层方…

    Java 2023年5月30日
    071
  • 【校招VIP】[产品][211][8分]按需求分类书写简历

    关注 【校招VIP】公众号,回复 【简历】,添加 校招顾问微信,即可获取 简历指导! 本份简历是一位 22届一本的产品同学简历,简历评分 8分 一、学员简历 二、指导意见 1 简历…

    Java 2023年6月5日
    070
  • 谷歌MapReduce经典论文翻译(中英对照)

    MapReduce: Simplified Data Processing on Large Clusters(MapReduce: 简化大型集群下的数据处理) 作者:Jeffre…

    Java 2023年6月8日
    066
  • java限制方法执行时间;Future使用

    public static void main(String[] args) { ThreadPoolTaskExecutor threadPoolTaskExecutor = n…

    Java 2023年5月29日
    079
  • JDK成长记5:LinkedList初探

    LinkedList初探 作为Java工程师,LinkedList你可能用的不多,大多你总是在new ArrayList。面试很多时候总是拿LinkedList和ArrayList…

    Java 2023年6月5日
    082
  • 自定义排序之数据库设计

    自定义排序之数据库设计 之前做过的项目有项需求,就是要对一个普通的列表进行自定义排序功能,当初构思了几个方案,各有所长,按需使用,下面就一一来介绍这几个方案。注:这里的自定义排序就…

    Java 2023年6月16日
    083
  • Java SE 代码块

    1、代码块 基本语法 [修饰符]{ 代码 }; 修饰符 可选,要写的话,也只能写 static 代码块分为两类,使用static修饰的叫静态代码块,没有static修饰的,叫普通代…

    Java 2023年6月7日
    073
  • CSS的简单了解

    Hello CSS- Original: https://www.cnblogs.com/41357wangsun/p/16528876.htmlAuthor: 叨叨不是刀刀Tit…

    Java 2023年6月6日
    068
  • 深入理解mysql锁与事务隔离级别

    一、锁 1、锁的定义 锁即是一种用来协调多线程或进程并发使用同一共享资源的机制 2、锁的分类 从性能上分类:乐观锁和悲观锁 从数据库操作类型上分类:读锁和写锁 从操作粒度上分类:表…

    Java 2023年6月13日
    079
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球