android中的JNI的DEMO

一:源代码

native-lib.cpp

#include "native-lib.h"

JNIEXPORT jint JNICALL
Java_com_example_jnidemo_MainActivity_add(JNIEnv* env, jobject, jint a, jint b) {
    return a + b;
}

JNIEXPORT jint JNICALL
Java_com_example_jnidemo_MainActivity_subtract(JNIEnv* env, jobject, jint a, jint b) {
    return a - b + 3;
}

JNIEXPORT jint JNICALL
Java_com_example_jnidemo_MainActivity_multiply(JNIEnv* env, jobject, jint a, jint b) {
    return a * b + 3;
}

JNIEXPORT jdouble JNICALL
Java_com_example_jnidemo_MainActivity_divide(JNIEnv* env, jobject, jint a, jint b) {
    if (b == 0) return 0;
    return static_cast<jdouble>(a) / static_cast<jdouble>(b);
}

native-lib.h

#ifndef NATIVE_LIB_H
#define NATIVE_LIB_H

#include <jni.h>

#ifdef __cplusplus
extern "C" {
#endif

JNIEXPORT jint JNICALL Java_com_example_jnidemo_MainActivity_add(JNIEnv* env, jobject, jint a, jint b);
JNIEXPORT jint JNICALL Java_com_example_jnidemo_MainActivity_subtract(JNIEnv* env, jobject, jint a, jint b);
JNIEXPORT jint JNICALL Java_com_example_jnidemo_MainActivity_multiply(JNIEnv* env, jobject, jint a, jint b);
JNIEXPORT jdouble JNICALL Java_com_example_jnidemo_MainActivity_divide(JNIEnv* env, jobject, jint a, jint b);

#ifdef __cplusplus
}
#endif

#endif // NATIVE_LIB_H

MainActivity

package com.example.jnidemo;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

    private native int add(int a, int b);
    private native int subtract(int a, int b);
    private native int multiply(int a, int b);
    private native double divide(int a, int b);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        int a = 10;
        int b = 5;

        TextView tv = findViewById(R.id.sample_text);
        StringBuilder sb = new StringBuilder();
        sb.append("Add: ").append(add(a, b)).append("\n");
        sb.append("Subtract: ").append(subtract(a, b)).append("\n");
        sb.append("Multiply: ").append(multiply(a, b)).append("\n");
        sb.append("Divide: ").append(divide(a, b)).append("\n");

        tv.setText(sb.toString());
    }
}

 CMakeLists.txt

尤其注意下面的第一行camke的版本要与settings中的SDK TOOL中的保持一致:cmake_minimum_required(VERSION 3.10.2)

# 设置CMake的最低版本要求
cmake_minimum_required(VERSION 3.10.2)

# 设置项目名称
project("native-lib")

# 添加共享库
# add_library函数用来定义库的名称、类型和源文件
add_library(
        # 设置库的名称
        native-lib

        # 设置库的类型为共享库
        SHARED

        # 提供库的源文件路径
        E:/a_own_codes/android_java/JNIdemo/app/src/main/cpp/native-lib.cpp)

# find_library函数用于查找系统中已存在的库,并设置其路径
find_library(
        # 设置路径变量的名称
        log-lib

        # 指定要查找的NDK库的名称
        log
)

# target_link_libraries函数用于将目标库与其依赖库链接在一起
target_link_libraries(
        # 指定目标库
        native-lib

        # 将目标库链接到NDK中包含的log库
        ${log-lib}
)

 代码结构

 二:关于NDK工具

2.1 AS中配置

 2.2 环境变量配置
 

 2.3验证安装

 

三:为什么使用JNI

JNI
JNI 全程:JNI(Java Native Interface),通俗翻译:Java本地方法
官方说法:提供一种Java字节码调用C/C++的解决方案,JNI描述的是一种技术。所以这里的Nativie的本地的意思就是C/C++,所以JNI通俗理解就是Java调用C/C++的方案技术。

NDK
NDK(Native Development Kit),通俗翻译:本地发展(扩展)工具
Android NDK 是一组允许您将 C 或 C++(“原生代码”)嵌入到 Android 应用中的工具,NDK描述的是工具集。

同样,把这里的Native理解成C/C++,那么NDK的简单理解就是能把C/C++编译成Java识别的工具模块。Android Studio中已经集成了NDK,所以才可以在Java代码中很方便就可以调用到C/C++的代码。网上有些示例是用NDK命令来编译cpp生成so,并调用测试,这里不做介绍。

Jni的开发背景:

需要调用Java语言不支持的依赖于操作系统平台特性的一些功能,比如

● 需要调用当前UNIX系统的某个功能,而Java不支持这个功能的时候,就要用到JNI
● 在程序对时间敏感或对性能要求特别高时,有必要用到更底层的语言来提高运行效率
● 音视频开发涉及到的音视频编解码需要更快的处理速度,这就需要用到JNI
● 为了整合一些以前的非Java语言开发的系统
● 需要用到早期实现的C/C++语言开发的一些功能或者系统,将这些功能整合到当前的系统或者新的版本中

其实就是为了调用C/C++代码

JNI是完善Java的一个重要功能,它让Java更加全面、封装了各个平台的差异性

JNI在 Android 开发里的主要应用场景:

● 音视频开发
● 热修复
● 插件化
● 逆向开发
● 等等…

这些都是比较复杂的模块,很多实现Java代码无法实现或者使用Java代码实现会很低效的情况。所以这些模块开发的就要提前掌握Jni相关技术才能实现复杂功能。其实这些概念,看一百遍也是很容易忘记的,只要记住一点就行了:

JNI就是Java为了调用C语言的技术,其中过程用到了NDK相关工具。

java-jni-c/c++ 关系图也是比较简单明了的:

Jni基础很简单,比如:Java 代码中加载so库,定义native方法,jni代码中执行简单的实现,相信很多人都是会的;

Jni的进阶知识:jni添加日志,复制对象的调用,C++调用Java方法,Jni方法的动态注册和静态注册,Jni报错分析等等,这些都是有一定的难度的,经过一定的学习了解就可以掌握了。

这些Jni相关知识的学习,不需要系统源码环境,只需要电脑安装Android Studio,安装模拟器或者有安卓真机调试验证就可以了。JNI在系统源码环境中也是有很多相关的代码和使用场景,如果是入门学习,优先使用Android Stduio 创建的项目会好入手很多。                        
原文链接:https://blog.csdn.net/wenzhi20102321/article/details/136291126

四:文件名称路径以及方法名的关系

在JNI(Java Native Interface)中,Java中的本地方法和C/C++中的实现方法之间通过特定的命名约定进行映射。这个命名约定由JNI定义,确保Java虚拟机能够正确找到并调用对应的本地实现方法。具体来说,这种映射关系由以下规则构成:

JNI 方法命名约定

  1. 前缀:所有的本地方法在C/C++实现中都以 Java_ 开头。
  2. 包名:将包名中的点号(.)替换为下划线(_)。
  3. 类名:直接使用类名。
  4. 方法名:直接使用方法名。
  5. 参数类型(可选):如果方法名相同且参数不同,参数类型也需要编码在方法名中。

例如,Java类中的方法签名如下:

package com.example.jnidemo;

public class Calculator {
    static {
        System.loadLibrary("calculator");
    }

    public native int add(int a, int b);
}

根据命名约定,这个方法在C文件中的实现应该是:

#include <jni.h>
#include "com_example_jnidemo_Calculator.h"

JNIEXPORT jint JNICALL Java_com_example_jnidemo_Calculator_add(JNIEnv *env, jobject obj, jint a, jint b) {
    return a + b;
}

命名规则详细解释

  • Java_: 前缀,所有JNI方法必须以这个前缀开头。
  • com_example_jnidemo: 包名,将包名中的 . 替换为 _
  • Calculator: 类名。
  • add: 方法名。

使用过程中如何映射

  1. 加载共享库

static {
    System.loadLibrary("calculator");
}

这行代码告诉Java虚拟机在加载类时加载名为 libcalculator.so 的共享库。System.loadLibrary("calculator") 会寻找 libcalculator.so 文件并将其加载到进程的地址空间中。 

        2.声明本地方法

public native int add(int a, int b);

        声明本地方法时,并没有提供实现,表示这个方法将在本地代码中实现。

        3.调用本地方法

        当Java代码中调用 add 方法时,JNI机制会查找对应的本地方法实现。根据命名约定,Java虚拟机会寻找名为 Java_com_example_jnidemo_Calculator_add 的C函数。

        4.映射过程:

       Java虚拟机加载 libcalculator.so 文件时,会建立共享库中的符号表。当调用 add 方法时,Java虚拟机根据命名约定查找符号表中的 Java_com_example_jnidemo_Calculator_add 函数地址。找到地址后,执行对应的C函数,实现本地方法调用。

        详细方法定义与调用以及方法体的代码见第一节

五:.so的位置

注意事项

*/01/*
原来源文件的路径写的是相对路径:
src/main/cpp/native-lib.cpp

报错:could not find souce file

# 提供库的源文件路径:
E:/a_own_codes/android_java/JNIdemo/app/src/main/cpp/native-lib.cpp

*/02/*

Invalidate Caches / Restart:清除所有缓存,并重启 IDE,适合解决缓存问题和一些难以解决的错误。
Just Restart:仅重启 IDE,不清除缓存,适用于普通的重启需求

*/03/*

[CXX5106] NDK was located by using ndk.dir property. This method is deprecated and will be removed in a future release. Please delete ndk.dir from local.properties and set android.ndkVersion to [21.4.7075529] in all native modules in the project. https://developer.android.com/r/studio-ui/ndk-dir

错误信息 [CXX5106] NDK was located by using ndk.dir property. This method is deprecated and will be removed in a future release. 表示使用了已弃用的方式来指定NDK路径。您需要更新配置,将ndk.dir从 local.properties 文件中移除,并使用 android.ndkVersion 配置(见上面的build.gradle文件中的ndkVersion '21.4.7075529')。

*/04/*

在Android Studio中,先点击“Clean Project”,点击“File” -> “Sync Project with Gradle Files”来同步项目,然后点击“Build” -> “Make Project”来构建项目。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/718119.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

DBeaver连接数据库

1、空白处右键点击 2、创建-连接 3、选择不同的数据库 4、修改信息 (mac)双击&#xff0c;连接&#xff0c;根据自己的需求重命名

VBA学习(2):Excel VBA初学者编写第一个宏

要在Excel中编写宏程序&#xff0c;首先需要了解VBA语言&#xff0c;而快速入门的技巧就是使用宏录制器。 宏录制器就像一台录音机&#xff0c;可以使用VBA监听和记录你在Excel中所做的一切操作。对于初学者来说&#xff0c;你可能不了解VBA&#xff0c;这里&#xff0c;我们会…

抖音用户新作品监控助手,第一时间获取博主作品信息。

声明&#xff1a; 本文以教学为基准、本文提供的可操作性不得用于任何商业用途和违法违规场景。本人对任何原因在使用本人中提供的代码和策略时可能对用户自己或他人造成的任何形式的损失和伤害不承担责任。包含关注&#xff0c;点赞等 抖音新作品监控助手系统是一个功能强大的…

ChatGPT-4o赋能科研:自然科学研究的新篇章

自然科学研究遵循严谨的科学方法论&#xff0c;包括文献调研、问题综述、试验设计、提出假设、数据清洗、统计诊断、大数据分析、经典统计模型&#xff08;回归模型、混合效应模型、结构方程模型、Meta分析模型&#xff09;、参数优化、机器/深度学习、大尺度模型构建与模拟、论…

持PMP证书可以免考申请CSPM-2国标证书!

一提到项目管理的专业认证&#xff0c;大家首先想到的肯定是以PMP为核心的PMI体系认证。当然也有BSI和IPMP等其他体系认证&#xff0c;但都是从国外引进的专业认证&#xff0c;我国始终缺少符合中国特色项目管理环境下的项目管理专业认证体系。 如今&#xff0c;更符合中国国情…

单细胞|RNA-seq ATAC-seq 联合分析

引言 本文[1]将介绍如何利用Signac和Seurat这两个工具&#xff0c;对一个同时记录了DNA可接触性和基因表达的单细胞数据集进行综合分析。我们将以一个公开的10x Genomics Multiome数据集为例&#xff0c;该数据集针对的是人体的外周血单核细胞。 数据准备 library(Signac)libra…

八股文之JVM

目录 1.JVM内存划分 2.JVM类加载过程 3.JVM垃圾回收机制GC 3.1.判断谁是垃圾 3.2.如何释放对应的内存 1.JVM内存划分 在一个Java程序运行起来之后&#xff0c;jvm就会从操作系统中申请一块内存&#xff0c;然后就会将该内存划分成多个部分&#xff0c;用于不同的用途。 …

【拥抱鸿蒙】HarmonyOS NEXT实现双路预览并识别文字

我们在许多其他平台看到过OCR功能的应用&#xff0c;那么HarmonyOS在这方面的支持如何呢&#xff1f;我们如何能快速使用这一能力呢&#xff1f;使用这一能力需要注意的点有哪些呢&#xff1f;就让我们一起来探究吧~ 【开发环境】 版本规则号&#xff1a;HarmonyOS NEXT版本类…

闭包表(Closure Table)

设计血缘关系&#xff08;data-lineage&#xff09;时&#xff0c;想到要使用的表模型。 表设计 节点记录表 - node CREATE TABLE lineages_node (name varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 节点名称,id bigint(20) unsigned NOT NULL AUTO_INCREM…

python图像处理库-PIL(Pillow)

PIL库全称为Python Imaging Library&#xff0c;即Python图像处理库&#xff0c;是一个在Python中用于处理图像的非常流行的库。 一、PIL介绍 这个库提供了广泛的文件格式支持、高效的内部表示以及相当强大的图像处理功能。 核心图像库旨在快速访问存储在几种基本像素格式中的数…

C#特性-CallerMemberName、CallerFilePath和CallerLineNumber的介绍和应用

介绍 在csharp中&#xff0c;CallerMemberName, CallerFilePath, 和 CallerLineNumber 是编译时常量&#xff0c;它们是csharp 5.0引入的特性&#xff0c;用于提供有关调用堆栈的信息&#xff0c;通常用于日志记录和调试。这些特性可以自动填充方法的参数&#xff0c;无需显式…

基于SpringBoot校园食堂订餐管理系统

文章目录 系统运行图概要整体架构流程技术名词解释 系统运行图 概要 随着校园人口的增加和生活节奏的加快&#xff0c;校园食堂的订餐管理面临着诸多挑战&#xff0c;传统的人工点餐方式已经不能满足日益增长的需求和期望。因此&#xff0c;本论文旨在设计和实现一种基于Java的…

图解Attention学习笔记

教程是来自https://github.com/datawhalechina/learn-nlp-with-transformers/blob/main/docs/ 图解Attention Attention出现的原因是&#xff1a;基于循环神经网络&#xff08;RNN&#xff09;一类的seq2seq模型&#xff0c;在处理长文本时遇到了挑战&#xff0c;而对长文本中…

IPD体系进阶:组织体系诊断7S模型

目录 1. IPD 变革说明 2. 麦肯锡 7S 模型 3. IPD 资源 1. IPD 变革说明 企业引入 IPD&#xff0c;最直接的原因在于&#xff1a; 要解决组织当下遇到的发展问题。 这个时候就离不开对自身的诊断。 这跟解决日常问题是一样的思路。 有这样一句爱因斯坦的名言&#xff0c…

垃圾回收管理系统设计

一、引言 随着城市化进程的加快&#xff0c;垃圾处理问题日益凸显。为了有效管理垃圾回收&#xff0c;提高资源利用效率&#xff0c;降低环境污染&#xff0c;本文设计了一套垃圾回收管理系统。该系统涵盖了数据收集与分析、智能监测与识别、资源调配与协调、用户参与与反馈、…

maven编译【-Dmaven.test.skip=true和-DskipTests=true的区别】

1、背景 我在执行maven编译时&#xff0c;遇到下面情况&#xff1a; 1、当执行命令为下面&#xff1a; mvn clean compile package install -Dmaven.wagon.http.ssl.insecuretrue -Dmaven.wagon.http.ssl.allowalltrue -Dmaven.wagon.http.ssl.ignore.validity.datestrue -Dra…

基于自编码器的心电图信号异常检测(Python)

使用的数据集来自PTB心电图数据库&#xff0c;包括14552个心电图记录&#xff0c;包括两类&#xff1a;正常心跳和异常心跳&#xff0c;采样频率为125Hz。 import numpy as np np.set_printoptions(suppressTrue) import pandas as pd import matplotlib.pyplot as plt import…

qss实现登录界面美化

qss实现登录界面美化 #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);// 去掉头部this->setWindowFlag(Qt::FramelessWindowHint);// 去掉空白部分th…

批量修改文件后缀名

背景引言 bat 文件是dos下的批处理文件。批处理文件是无格式的文本文件&#xff0c;它包含一条或多条命令。它的文件扩展名为 .bat 或 .cmd。在命令提示下输入批处理文件的名称&#xff0c;或者双击该批处理文件&#xff0c;系统就会调用cmd.exe按照该文件中各个命令出现的顺序…

鸿蒙 用tabs的 divider 属性 添加分割线,非常好用

divider10DividerStyle | null 用于设置区分TabBar和TabContent的分割线样式设置分割线样式&#xff0c;默认不显示分割线。 DividerStyle: 分割线的样式&#xff1b; null: 不显示分割线。 添加前&#xff1a; 添加后的效果&#xff1a;