当前位置: 首页 > news >正文

NDK(四):Native与Java互调

文章目录

  • 一、概述
  • 二、Native与Java层互调
    • 2.1 用例介绍
    • 2.2 Java调用Native代码
    • 2.3 Native调用Java代码

一、概述

JNI(全名Java Native Interface)Java native接口,它可以让一个运行在Java虚拟机中的Java代码被调用或者调用native层的代码。简单理解为就是一个连接Java层和Native层的桥梁。

本文我们就来分析一下 Java 与 Native 是如何实现互调的。

关联文章:

  • NDK(一):NDK的集成
  • NDK(二):JNI的数据结构
  • NDK(三):JNIEnv解析
  • NDK(四):Native与Java层互调
  • NDK(五):JNI静态注册与动态注册

二、Native与Java层互调

2.1 用例介绍

实现一个下图所示的功能。

  • 下图中有3个按钮,顶部两个按钮一个是让 count 值自增1,由 Java 层实现;第二个按钮是让 count 值自减1,由 Native 层实现;第三个按钮是用于显示当前 count 值的控件。
  • 上面两个控件显示的文本是从 JNI 层获取,实现了 Java 对 Native 层的调用。
  • 第三个控件数据的更新是通过 JNI 来实现的,实现了 Native 层对 Java 层的调用。

在这里插入图片描述

2.2 Java调用Native代码

public class MainActivity extends AppCompatActivity {

    static {
        System.loadLibrary("jnitestdemo");
    }
    TextView textView3;
    int count = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView textView = findViewById(R.id.sample_text);
        // Java调JNI层获取数据,这部分已经在 [NDK(一):NDK 的集成]部分分析过了。
        textView.setText(stringFromJNI());
        textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                count++;
                textView3.setText(String.valueOf(count));
            }
        });

        TextView textView2 = findViewById(R.id.sample_text_2);
        // Java调JNI层获取数据
        textView2.setText(staticStringFromJNI());
        textView2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
            	// Java调JNI层来实现对count的自增操作和对textView3控件的更新。
                decreaseCountValue();
            }
        });

        textView3 = findViewById(R.id.sample_text_3);
        textView3.setText(String.valueOf(count));
    }

    public native String stringFromJNI();
    public static native String staticStringFromJNI();
    // JNI层实现对count的自增操作和对textView3控件的更新
    public native void decreaseCountValue();
}

JNI 层:native-libcpp

#include <jni.h>
#include <string>

// 静态注册
extern "C" JNIEXPORT jstring JNICALL
Java_com_elson_jnitestdemo_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "count+=1";
    return env->NewStringUTF(hello.c_str());
}

// 静态注册
extern "C"
JNIEXPORT jstring JNICALL
Java_com_elson_jnitestdemo_MainActivity_staticStringFromJNI(
        JNIEnv *env,
        jclass clazz) {
    std::string hello = "count-=1";
    return env->NewStringUTF(hello.c_str());
}

2.3 Native调用Java代码

#include <jni.h>
#include <string>

// Java_decreaseCountValue是动态注册的,所以命名可以不遵寻JNI静态注册的规范。
extern "C"
JNIEXPORT void JNICALL
Java_decreaseCountValue(JNIEnv *env, jobject thiz) {
	// 查找某个对象的字段或者方法,都是通过这个类的对象去查找的,即jclass。
	// 调用某个对象的方法,都是通过这个对象去调用的,即jobject。 
	
	// ----- 获取MainActivity.count字段 -------
    // 1.1 先获取MainActivity类的对象。
    jclass clazz = env->GetObjectClass(thiz);
    // 1.2 通过类对象jclass访问属性字段或方法的id。
    jfieldID countFieldId = env->GetFieldID(clazz, "count", "I");
    // 1.3 通过字段id获取到字段对应的值。这里获取MainActivity.count的值。
    jint oldCount = env->GetIntField(thiz, countFieldId);
    // 1.4 更新MainActivity.count的值
    env->SetIntField(thiz, countFieldId, oldCount-1);

    jint newCount = env->GetIntField(thiz, countFieldId);
	
	// ----- 获取MainActivity.textView3字段 -------
	// 2.1 获取textView3字段id。
    jfieldID textViewFieldId = env->GetFieldID(clazz, "textView3", "Landroid/widget/TextView;");
     // 2.2 需要调用textView.setText()方法,所以先要获取到textView的类对象jclass。
    jobject textViewObject = env->GetObjectField(thiz, textViewFieldId);
    jclass textViewClazz = env->GetObjectClass(textViewObject);
    // 2.3 获取到textView.setText()方法id。
    jmethodID methodId = env->GetMethodID(textViewClazz, "setText", "(Ljava/lang/CharSequence;)V");
    
    // ----- 对TextView进行赋值 -------
    char buf[64];
    sprintf(buf, "%d", newCount);
    // 3.1 构建一个jstring。
    jstring pJstring = env->NewStringUTF(buf);
	// 3.2 调用textView.setText()方法进行赋值。
    env->CallVoidMethod(textViewObject, methodId, pJstring);
}


static const JNINativeMethod nativeMethods[] = {
        {"decreaseCountValue", "()V", (void *) (Java_decreaseCountValue)},
};

// 添加动态注册入口
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reversed) {
    JNIEnv *env = NULL;
    // 初始化JNIEnv
    if(vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK){
        return JNI_FALSE;
    }
    // 找到需要动态动态注册的JNI类
    jclass jniClass = env->FindClass("com/elson/jnitestdemo/MainActivity");
    if(nullptr == jniClass){
        return JNI_FALSE;
    }
    // 动态注册
    env->RegisterNatives(jniClass, nativeMethods, sizeof(nativeMethods)/sizeof(JNINativeMethod));
    // 返回JNI使用的版本
    return JNI_VERSION_1_6;
}

小结:

  • 查找某个对象的字段或者方法,都是通过这个类的对象去查找的,即jclass。
  • 调用某个对象的方法,都是通过这个对象去调用的,即jobject。

相关文章:

  • SpringSecurity
  • 机器学习:基于逻辑回归对优惠券使用情况预测分析
  • 米哈游春招后端-2023.03.19-第一题-米哈游的RBG矩阵-简单
  • 教你精通JavaSE语法之第九章、抽象类和接口
  • 龙芯2K1000开发板拷贝镜像到固态
  • 前端计算文件 hash
  • ChatGPT写作文章-快速使用ChatGPT不用注册方式
  • 2万字60道MySQL经典面试题总结(附答案)
  • Maven生命周期、mvn命令、Maven插件
  • 【ChatGPT】这是一篇ChatGPT写的关于Python的文章
  • Ubuntu之NVIDIA GeForce显卡驱动安装
  • 【华为OD机试 2023最新 】 通信误码(C++)
  • 为Activity的启动添加约束条件
  • 2022年河南省高等职业教育技能大赛云计算赛项竞赛方案
  • 时间序列教程 一、数据的三个组成部分
  • 【MySQL经典案例分析】 Waiting for table metadata lock
  • 【面试系列】之二:关于js原型
  • const let
  • k个最大的数及变种小结
  • React as a UI Runtime(五、列表)
  • UEditor初始化失败(实例已存在,但视图未渲染出来,单页化)
  • Vue2 SSR 的优化之旅
  • 从输入URL到页面加载发生了什么
  • 浮动相关
  • 如何胜任知名企业的商业数据分析师?
  • 如何用Ubuntu和Xen来设置Kubernetes?
  • 写代码的正确姿势
  • 掌握面试——弹出框的实现(一道题中包含布局/js设计模式)
  • hi-nginx-1.3.4编译安装
  • ionic入门之数据绑定显示-1
  • LIGO、Virgo第三轮探测告捷,同时探测到一对黑洞合并产生的引力波事件 ...
  • 阿里云API、SDK和CLI应用实践方案
  • 阿里云重庆大学大数据训练营落地分享
  • 大数据全解:定义、价值及挑战
  • ​Spring Boot 分片上传文件
  • # Python csv、xlsx、json、二进制(MP3) 文件读写基本使用
  • #[Composer学习笔记]Part1:安装composer并通过composer创建一个项目
  • (附源码)springboot金融新闻信息服务系统 毕业设计651450
  • (附源码)基于SSM多源异构数据关联技术构建智能校园-计算机毕设 64366
  • (附源码)计算机毕业设计SSM疫情下的学生出入管理系统
  • (转)人的集合论——移山之道
  • .Net Redis的秒杀Dome和异步执行
  • .Net 中的反射(动态创建类型实例) - Part.4(转自http://www.tracefact.net/CLR-and-Framework/Reflection-Part4.aspx)...
  • .NetCore实践篇:分布式监控Zipkin持久化之殇
  • @transactional 方法执行完再commit_当@Transactional遇到@CacheEvict,你的代码是不是有bug!...
  • @在php中起什么作用?
  • [14]内置对象
  • [3300万人的聊天室] 作为产品的上游公司该如何?
  • [51nod1610]路径计数
  • [Android Pro] Notification的使用
  • [CTF]php is_numeric绕过
  • [FC][常见Mapper IRQ研究]
  • [flask]http请求//获取请求体数据
  • [k8s系列]:kubernetes·概念入门
  • [leetcode] 四数之和 M