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)

大家都在看

  • 如何求源码,反码,补码

    最近有朋友问起这些,于是就简单的讲一下吧(只讲求法,没有包含真正的意义)。 源码怎么求 //原码就是早期用来表示数字的一种方式,用最高位表示符号位,最高位为’1’表示负号,’0’表…

    Java 2023年6月5日
    087
  • [学习笔记] Java枚举

    在Java中,枚举是一种特殊的类,一般用于表示一组常量; 定义枚举时使用 enum关键字,各个常量使用逗号分隔; 也可以在类的内部定义枚举: 每个枚举都以内部类的形式实现,且所有的…

    Java 2023年6月5日
    082
  • MybatisPlus核心功能——实现CRUD增删改查操作 (包含条件构造器)

    CRUD 官方文档:https://baomidou.com/(建议多看看官方文档,每种功能里面都有讲解)【本文章使用的mybatisplus版本为3.5.2】 条件构造器 一般都…

    Java 2023年6月14日
    080
  • 继承

    基本概念 扩充一个类已有的功能 优点 父类定义公共的内容,方便统一修改 整体减少代码量 添加新类方便 语法 class 子类 extends 父类{} 子类又叫派生类 父类又叫超类…

    Java 2023年6月6日
    082
  • 组合总和 II

    题目介绍 给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。candidates…

    Java 2023年6月8日
    0129
  • [spring]spring管理的入门项目快速搭建

    1.spring简介 Spring框架是一个开源的应用程序框架,是针对bean的生命周期进行管理的轻量级容器。 Spring解决了开发者在J2EE开发中遇到的许多常见的问题,提供了…

    Java 2023年6月6日
    089
  • Factory Pattern模式(简单工厂、工厂方法、抽象工厂模式)

    与工厂相关的的三个设计模式2020-11-08 15:03:29 简单工厂模式:说白就是,间接脱离了new 创建对象,而是直接从工厂中获得对象。 简单工厂:不是用new创建对象,而…

    Java 2023年6月9日
    079
  • 分布式系统中的一些问题

    一. CAP理论,BASE理论? CAP: C:强一致性,保证每一节点(微服务)统一时间点数据的完全一致 A:可用性,整个系统是一直可用的,而且是正常响应时间。不允许出现用户访问失…

    Java 2023年6月7日
    068
  • 面试突击68:为什么 TCP 需要 3 次握手?

    TCP 三次握手是一道经典的面试题,它是指 TCP 在传递数据之前,需要进行 3 次交互才能正式建立起连接,并进行数据传递。TCP 之所以需要 3 次握手是因为 TCP 双方都是全…

    Java 2023年5月29日
    0106
  • 提高学习效率的工具

    浏览器 浏览器:谷歌(推荐,后面都是基于谷歌的,要懂得如何高效地上网)、edge… 插件:SuperCopy(超级复制)、AdBlock(拦截广告)、Tampermon…

    Java 2023年6月5日
    088
  • 顺序结构(Java)

    基本介绍 Java的基本结构就是顺序结构,除非特别指明,否则就按照顺序一字一句执行 顺序结构是最简单的算法结构 语句与语句之间,框与框之间是按照从上到下的顺序进行,它是由若干个依次…

    Java 2023年6月9日
    066
  • Grafana 安装

    环境 CentOS 8 1. 安装 sudo nano /etc/yum.repos.d/grafana.repo 写入配置 [grafana] name=grafana base…

    Java 2023年6月9日
    082
  • 建造者模式

    建造者模式:使用多个简单的对象一步一步构建成一个复杂的对象,适用于一些基本的组成不变,但是可以有多种组合,也就是所谓的”套餐”。不多说,直接上代码 第一步创…

    Java 2023年6月9日
    078
  • Java中对象池的本质是什么?(实战分析版)

    对象池顾名思义就是存放对象的池,与我们常听到的线程池、数据库连接池、http连接池等一样,都是典型的池化设计思想。 对象池的优点就是可以集中管理池中对象,减少频繁创建和销毁长期使用…

    Java 2023年5月29日
    0101
  • 【转】京东评价系统海量数据存储设计

    概述 京东的商品评论目前已达到数十亿条,每天提供的服务调用也有数十亿次,而这些数据每年还在成倍增长,而数据存储是其中最重要的部分之一,接下来就介绍下京东评论系统的数据存储是如何设计…

    Java 2023年6月7日
    080
  • 总结一下今天所学的知识9.18

    一种是将client和controller层实现一个共同的接口 — 这种方式的话耦合度非常高,而且形参中的注解不会被继承,所以controller中仍然需要注明形参列表…

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