JNI开发最佳实践

JNI 技术详解:从 Android AudioEffect 源码分析 通过分析模块的源码,我们深入了解了 JNI 在 Android 中的应用。JNI 提供了 Java 与本地代码之间的桥梁,使得开发者能够充分利用底层库的性能和功能。然而,JNI 的使用也带来了复杂的内存管理和类型转换问题,开发者需要谨慎处理这些问题,以避免内存泄漏和程序崩溃。尽量减少 JNI 调用的频率,避免频繁的 Java 与本地代码之间的切换。在 JNI 中正确处理 Java 对象的引用,避免内存泄漏。使用CheckJNI工具检查 JNI 代码的正确性。 阅读详情

今天逛论坛时意外发现一个很给力的小视频,嘿嘿嘿。传送门 。这是一个美国的哥们录制的一个JNI开发入门的小案例。看了一遍,还不错,把整个流程记录一下。然后补充一些知识。恩。Let’s begin.

转载请注明出处:
优快云:天道酬勤
本文地址:http://blog.youkuaiyun.com/Hello_Chillax/article/details/50920766

软件开发,环境很重要,说一下我的编程环境:

Operation System:Mac OS 10.10.4
JDK:jdk1.8
IDE:Android Studio:2.1 Preview1


一. 举个小栗子。


1. 首先,新建工程。工程名随意。

贴一下MainActivity的代码。

public class MainAty extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView tv= (TextView) findViewById(R.id.tv);
        tv.setText(getStringFromNative());
    }
    static {
        System.loadLibrary("first-jni");
    }
    public native String getStringFromNative();
}

现在我们唯一要做的事情就是实现这个native方法。为了达到这个目的,我们需要分以下几步去做。


2. 编译MainActivity文件,生成对应的字节码文件。

AndroidStudio —> build —> make project (这一步的快捷键是command + F9)

然后我们找到这个字节码文件。如果你对编译有一些了解,应该可以猜到字节码文件在哪里。这里给出路径。

《project name》—> 《module name》—> build —>intermediates —> classes —> debug —> 《包名》—>MainActivity.class


3. 使用javah命令生成对应的.h头文件。

上面我们得到了字节码文件的路径,接下来我们要生成对应的头文件。

打开AndroidStudio 的terminal终端,然后执行以下命令:

cd app/src/main

然后执行下面一段命令,有点长,不要急,一会儿我会解释。

javah -d jni -classpath /Users/MAC/Library/Android/sdk/platforms/android-23/android.jar:../../build/intermediates/classes/debug com.mac.jjj.MainAty

其中“/Users/MAC/Library/Android/sdk/platforms/android-23/android.jar”这一段是android.jar的路径,因为涉及到了Activity,所以要加上Activity的源码,不然会报错。

然后“com.mac.jjj”是我的包名。

另外要注意个小细节:
在android.jar 的路径和包名之间,有一个英文的“:”英文冒号,如果你的系统是Windows,记得换成“;”英文分号;如果你的系统是Linux或者Mac,则用英文的“:”英文冒号。(不同的系统连接符不一样,记住就行)

执行上面的命令之后,你的工程应该变成了这样.

这里写图片描述

可以看到,我们成功得到了.h文件。打开后可以看到对应的native方法。


4. 实现native方法。

我们把上面得到的.h文件拷贝一份,实现对应的方法。

然后我们的工程多了一个.cpp文件。(我比较喜欢cpp,所以这里用cpp演示,c语言写起来差不多)

这里写图片描述

然后我们大刀阔斧,把main.app中没用的东西先删了,只留下native方法的声明,然后实现这些方法。

/* DO NOT EDIT THIS FILE - it is machine generated */
#include "com_mac_jjj_MainAty.h"

JNIEXPORT jstring JNICALL Java_com_mac_jjj_MainAty_getStringFromNative
  (JNIEnv * env, jobject obj){

        return env->NewStringUTF("Hello From Jni ! ");
  }

很简单,一行代码。

(这个步骤,在Windows下有个坑,视频里提到了,Windows用户可以去看一看。。。)


4. 配置ndk。

在运行项目之前,我们需要先配置一下ndk。

先去官网下载一下ndk。传送门
需要个梯子,如果你没有梯子,可以去这里下载。AndroidDevTools

下载好后,解压。然后在local.properties文件中配置ndk。

sdk.dir=/Users/MAC/Library/Android/sdk//SDK路径
ndk.dir=/Users/MAC/Library/Android/ndk//NDK路径

接下来,我们需要配置生成的.so文件名称。

更改module的build.gradle文件。
在defaultConfig下添加如下内容:

ndk{
            moduleName "MyFirstSoLib"//设置.so库的名称
            abiFilter "armeabi"//设置.so库的cpu支持版本。默认支持所有版本(如 arm,x86等。。)
}

然后把MainActivity中加载的Library的名字改一下:

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


4. 运行一下。

如果你上面的步骤都正确的话,那么你就搞定了第一个jni程序。

这里写图片描述


5. 一点小思考。

对于jni和ndk,有很多人傻傻分不清楚。jni提供了一种Java和C/C++交互的接口,而ndk是为了jni开发而开发的一组工具包。

也就是说,想用c/c++开发Android部分功能,可以没有ndk,但是必须使用jni。

使用ndk开发的好处:简单,不用手动编写Android.mk文件和Application.mk文件(通过参数进行配置就行)

其中:Android.mk文件主要用来设置.so库的名称和需要参与编译的源文件地址。Application.mk主要用来配置CPU架构平台的类型。


二. JNI的数据类型和类型签名。

上面我们虽然实现了在Java中调用native方法。但是我们实现的功能也太简单了。打印个字符串没啥用,并且我们还没说怎么在native方法中调用Java方法。


1.首先,我们需要了解一下数据类型。

jni中的数据类型分为两种:基本类型和引用类型。

基本类型对应表:

JNI类型Java类型
jbooleanjboolean
jbytebyte
jcharchar
jshortshort
jintint
jlonglong
jfloatfloat
jdoubledouble
voidvoid

引用类型对应表:

JNI类型Java类型
jobject[]Object
jclassClass
jstringString
jobjectArrayObject[]
jbooleanArrayboolean[]
jbyteArraybyte[]
jcharArraychar[]
jshortArrayshort[]
jintArrayint[]
jlongArraylong[]
jfloatArrayfloat[]
jdoubleArraydouble[]
jthrowableThrowable

2.jni的类型签名。

jni的类型签名表示了一个特定的Java类型,这个类型可以是方法和类,也可以是数据类型。

2.1.类的签名。

类的签名:“L + 包名 + 类名 + ; ”

栗子:java.lang.String的签名为:Ljava/lang/String

2.1.基本数据类型的签名。

基本数据类型的签名采用一个大写字母表示。

基本数据类型的签名对应表:

Java类型签名
booleanZ
longJ
byteB
charC
shortS
intI
floatF
doubleD
voidV

(ps:可以看到,基本数据类型的签名是有规律的,除了boolean和long之外,其他的都是首字母大写。boolean特殊是因为字母B已经被byte占了,long特殊是因为字母L已经被类的签名占了。)

对象和数组的签名对应表:

Java类型签名
char[][C
float[][F
double[][D
long[][J
String[][Ljava/lang/String;
Object[][Ljava/lang/Object;

(ps:这个也有规律,对于数组来说,签名为:“[ + 类型签名”)

方法的签名对应表:

方法的签名为(参数类型签名)+ 返回值类型签名。

举个例子,规律显而易见。

方法签名
int fun1()()I
void fun2(int i)(I)V
boolean fun3(int a,double b,int[] c)(ID[C)Z
boolean fun4(int a,String b,int[] c)(ILjava/lang/String;[I)Z

三. JNI调用Java方法实例。

首先我们要了解一下,从native调用Java方法的流程:

  1. 找到Java中的某个Class(需要类的全路径),
  2. 得到方法的ID(需要1中的Class和方法签名)
  3. 调用Java方法(需要1中的Class和2中的方法ID)

我们还是用上面的那个栗子,修改一下,实现native调用Java。
我们主要实现的功能为:

Java调用native方法,然后native方法反过来调用Java方法,并传递一个字符串,在Java中显示出来。


1. 首先在Java中定义一个静态方法,以供native调用。

  public static void methodCalledByJni(String msg){
        tv2.setText(msg);//把结果显示到TextView上
    }

2. 编译工程生成.class文件。

步骤和第一个例子一样。。。

2. 生成对应的.h头文件。

步骤和第一个例子一样。。。

3. 在对应的.cpp文件中实现native方法。

/*
 * Class:     com_mac_jjj_MainAty
 * Method:    callJavaMethod
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_mac_jjj_MainAty_callJavaMethod
        (JNIEnv * env,  jobject obj){
    jclass cls=env->FindClass("com/mac/jjj/MainAty");//找到对应的class
    jmethodID id=env->GetStaticMethodID(cls,"methodCalledByJni","(Ljava/lang/String;)V");//找到对应的唯一的方法id
    jstring msg=env->NewStringUTF("msg send by callJavaMethod");
    env->CallStaticVoidMethod(cls,id,msg);//调用Java方法
}

4. 运行一下看看。

这里写图片描述


四. 写在最后。


JNI开发并不能明显提高App的整体性能,相反,这是一个很重量级的操作,我们在使用时应该权衡利弊,不能为了“JNI而JNI”,就像官网说的那样:
The NDK is not appropriate for most novice Android programmers, and has little value for many types of Android apps. It is often not worth the additional complexity it inevitably brings to the development process.

demo:传送门

JNI详解中文版本 JNI 调用规范和注意要点1.1版本,中文版本 立即下载

相关推荐

淘宝链接跳转微信全攻略:自建合规中转页实现私域引流

在跨平台运营中,链接跳转是连接不同生态、实现流量引导的关键技术。其核心原理是通过服务器端或前端逻辑,将用户从一个平台的链接安全引导至目标页面,同时规避平台间的访问限制。这项技术的核心价值在于打破数据孤岛,实现跨平台用户沉淀与精细化运营,广泛应用于电商引流、私域流量构建和跨平台营销等场景。本文聚焦于**淘宝短链**与**企业微信**之间的跳转难题,提供了一套基于自建中转页面的完整工程解决方案,手把手教你如何通过合规的技术手段,将淘宝流量高效、安全地引导至微信生态,并实现数据追踪与客户分流。

weixin_34185512的博客 411

使用JNI加载JAVA虚拟机

  在C中,直接使用JNI加载虚拟机,也是很有意思的想法。   这个工作不难,吾已经完成了。下面这个代码不是我的代码,没有真正测试过。以后有机会再测试。 #include <jni.h> using namespace std; int main(const int argc, const char** argv) { JavaVMOption options[7]; ...

柳鲲鹏 1226

从OFED到rdma-core:手把手带你搞定Linux下RDMA开发环境的选型与搭建

本文详细介绍了在Linux系统下搭建RDMA开发环境的完整流程,涵盖OFED与rdma-core的选型对比及分步安装指南。针对高性能计算和分布式存储需求,解析RDMA技术栈的核心组件,提供环境验证与性能测试方法,帮助开发者快速构建稳定高效的开发环境。特别适合需要优化网络性能的工程师参考。

weixin_26905487的博客 225

jin版本

Version Information GetVersion jint GetVersion(JNIEnv *env);Returns the version of the native method interface. For Java SE Platform 21 and later, it returns JNI_VERSION_21. The following table gives the version of JNI included in each release of the Java

ljklxlj的专栏 525

机械臂电机力矩计算

设计 6 轴机械臂时,电机力矩计算是确保机械臂负载能力、运动精度和安全性的核心环节,需围绕和两大核心展开,结合机械臂结构参数(如关节长度、质量分布)、负载需求(如末端负载重量、惯性)和运动参数(如加速度、角速度)逐步推导。

ZPC8210的博客 1857

《爬虫和逆向教程》 - 专栏介绍和目录

本专栏为爬虫初学者和进阶开发者量身定制的爬虫和逆向学习园地。为你提供全面而深入的爬虫和逆向技术指导,从入门到精通,从基础理论到高级实战,助你在数据的海洋中畅游,挖掘出有价值的信息。通过本专栏的学习,你将具备独立开发和优化爬虫程序的能力,及逆向分析能力和项目开发能力,成为爬虫领域的佼佼者。

数据知道的博客 2万+

OpenJDK System.loadLibrary源码剖析

OpenJDK System.loadLibrary源码剖析 System.loadLibrary是用于通知JVM加载Native so的,so加载成功后,在/proc/self/maps中可以看到so已经被加载到内存中。 熟悉系统层开发同学可以猜到,这基本等同于dlopen/LoadLibrary调用,接下来我们通过OpenJDK源码来分析一下。 下载OpenJDK源码:https://github.com/openjdk/jdk tag:jdk8-b120 1. System.java 搜索loadLi

胡超的学习日志 1028

华为OD新系统机试真题 4.26 -最大化游戏试玩资格分发

华为OD机试新系统真题【最大化游戏试玩资格分发】,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。华为OD新系统机试 4月26号真题【最大化游戏试玩资格分发】。

qq_45776114的博客 826

JNI文档总结

文章目录Java Native Interface OverviewChapter 2 Design OverviewJNI Interface Functions and PointersCompiling, Loading and Linking Native MethodsResolving Native Method NamesNative Method ArgumentsReferencing Java ObjectsGlobal and Local References局部/全局引用局部引用全局

小矿工的专栏 617

SAP FICO 内部往来对账功能开发说明书(包括测试样例、程序代码仅作参考,不保证一定可以运行)

SAP FICO 内部往来对账功能开发说明书(包括开发源代码、测试样例、FS)

我好像病了的博客 1223

基于STM32的多传感器融合的设施农业小型搬运机器人避障控制系统设计

针对设施农业场景中狭窄通道、障碍物多样(如农机具、作物植株、水管)的特点,设计一款基于 STM32 的小型搬运机器人避障控制系统。系统通过多传感器融合实现 360° 环境感知,采用模糊 PID 控制算法实现平滑避障,满足温室、大棚等场景的搬运需求。通过在温室环境测试,系统可实现对直径≥5cm 障碍物的有效检测(检测距离误差≤5%),避障转向半径≤30cm,平均功耗≤15W。后续可通过增加激光雷达(如 TFmini)提升远距离障碍物检测能力,结合 SLAM 算法实现路径规划。

weixin_42300449的博客 860

Java Native Interface JDK8使用JNI 示例

使用Java Native Interface (JNI)可以让Java程序调用本地(C/C++)代码。以下是一个示例,通过创建一个简单的JNI应用程序来演示如何使用JNI在JDK8中调用本地代码。

开心杨的个人博客 648

使用静态库在嵌入式系统中进行开发

静态库是一种包含预编译对象代码的文件,它可以与应用程序链接在一起,并在编译时将库的代码复制到最终的可执行文件中。静态库是包含预编译对象代码的文件,可以与应用程序链接在一起,并在编译时将库的代码复制到最终的可执行文件中。需要注意的是,由于嵌入式系统的资源限制,开发人员应该仔细选择需要包含在静态库中的功能,并避免引入不必要的依赖关系。需要注意的是,由于嵌入式系统的资源限制,开发人员应该仔细选择需要包含在静态库中的功能,并避免引入不必要的依赖关系。的静态库文件,可以在嵌入式系统的应用程序中使用它了。

ZrElixir的博客 203

Android的JNI开发全面介绍与最佳实践

JNI全称是Java Native Interface,为Java本地接口,是连接Java层与Native层的桥梁。在Android进行JNI开发时,可能会遇到couldn't find "xxx.so"问题,或者内存泄漏问题,或者令人头疼的JNI底层崩溃问题。Java层如何调用Native方法?Java方法的参数如何传递给Native层?而Native层又如何反射调用Java方法?这些问题在本文将得到答案,带着问题去阅读会事半功倍,接下来我们开始全方位介绍与最佳代码实践。

徐福记456 3万+

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

java调用 jni 太多好吗_JNI开发中,你需要知道的一些建议

原标题:JNI开发中,你需要知道的一些建议转自:https://blog.csdn.net/hejjunlin/article/details/80970820本文原文是:http://developer.android.com/training/articles/perf-jni.html,翻译费了我不少功夫,但是我自己收获也很大。JNI全称Java Native Interface。它为Jav...

weixin_35740588的博客 448

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Android JNI开发指南

接下来,我应该整理开发步骤。调试技巧也很重要,比如使用__android_log_print输出日志,在Android Studio中调试C/C++代码的步骤,以及处理崩溃时的addr2line工具使用。最后,常见问题部分需要涵盖UnsatisfiedLinkError的可能原因,比如库名不正确或ABI不匹配,JNI引用管理的问题,以及如何解决类型签名错误。然后是加载本地库和调用native方法,这里需要强调System.loadLibrary的正确使用,以及包名和库名之间的关系,避免常见的加载失败问题。

缘来的精彩的博客 1281

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

JNI开发总结

Android Ndk开发常用网站收集,真正的高手并不是掌握所有的API而是需要的时候可以快速的找到要使用的API。 基础知识请移步:http://blog.csdn.net/xyang81/article/details/41777471 JNI动态加载: http://www.cnblogs.com/skywang12345/archive/2013/05/23/3092491.html J...

mandagod的博客 280

JNI编程最佳实践

本文转载自:http://www.360doc.com/content/10/0910/15/2705099_52644635.shtmlJava? 本机接口(Java Native Interface,JNI)是一个标准的 Java API,它支持将 Java 代码与使用其他编程语言编写的代码相集成。如果您希望利用已有的代码资源,那么可以使用 JNI 作为您工具包中的关键组件 —— 比如在面向服务架构(SOA)和基于云的系统中。但是,如果在使用时未注意某些事项,则 JNI 会迅速导致应用程序性能低下且不稳

lovefqing的专栏 1564

JNI编程指南中文版资源下载:深入理解JNI,促进Java与本地代码交互

JNI编程指南中文版资源下载:深入理解JNI,促进Java与本地代码交互 【下载地址】JNI编程指南中文版资源下载 探索Java与本地代码交互的奥秘,《JNI编程指南中文版》为你打开一扇技术之门。这份PDF电子书是Java开发者的宝贵资源,深入剖析Java Native Interface(JNI)技术,从基础原理到高级...

gitblog_06729的博客 867

JNI性能优化与跨平台应用开发

在当今的软件开发领域,Java作为一种广泛使用的编程语言,以其跨平台性和强大的库支持而备受青睐。然而,在某些特定场景下,Java的局限性也日益凸显。例如,当需要与本地库或硬件设备进行交互时,Java的纯虚拟机特性就变得力不从心。这时,JNI(Java Native Interface)应运而生,它为Java程序提供了与本地代码交互的桥梁。JNI的出现,源于对Java语言在特定领域应用局限性的反思。在图形处理、高性能计算、嵌入式系统等领域,Java的运行效率往往无法满足需求。

我是Java程序员廖志伟,感谢朋友们的支持!不定期贡献一篇高品质、过万文字、图文并茂且附有视频解说、满载代码示例注释的良心之作,坚决杜绝粗制乱造。 1133

JNI

JNI注意事项

Cons_Step_By_Step 821

JNI 使用,原来我一直错

转自:  http://www.ibm.com/developerworks/cn/java/j-jni/ 最好看原版吧,排版非常好,这里粘贴是为了备份一下!   Java 环境和语言对于应用程序开发来说是非常安全和高效的。但是,一些应用程序却需要执行纯 Java 程序无法完成的一些任务,比如: JNI 的发展 JNI 自从 JDK 1.1 发行版以来一直是 Java 平台的一部

6687

JNI基础知识总结

JNI(Java Native Interface)是Java提供的一种编程框架,用于实现Java代码与本地(Native)代码(如C、C++等)之间的交互。JNI允许Java应用程序调用本地代码,并且本地代码可以调用Java代码,实现更高性能的操作或访问底层资源。

金戈鐡馬 3669

JNI-By-Examples 开源项目教程

JNI-By-Examples 开源项目教程 项目介绍 JNI(Java Native Interface)是Java平台的一部分,它允许Java代码与其他语言编写的代码交互。JNI-By-Examples是一个通过实例学习JNI技术的GitHub仓库,由用户thefangbear维护。这个项目通过一系列实际的例子,展示了如何在Java应用程序中调用C/C++代码,帮助开发者理解和掌握JNI的基本...

gitblog_00264的博客 405

JNI编程指南

原链接:http://www.ibm.com/developerworks/cn/java/j-jni/ 使用 Java Native Interface 的最佳实践

hubinbin595959的专栏 357

使用 Java Native Interface 的最佳实践(JNI)

避免最常见的 10 大 JNI 编程错误的技巧和工具 级别: 中级 Michael Dawson, 高级软件开发人员, IBM Graeme Johnson, J9 虚拟机开发经理, IBM Andrew Low, STSM,J9 虚拟机, IBM 2009 年 7 月 27 日 Java™本机接口(Java Native Interface,JNI)是一个标准

u012814377的专栏 1141
上一篇: 备战Android实习(Java基础知识篇)
下一篇: 备战Android实习(计算机基础篇)
肖小的人儿
博客等级 码龄12年 29粉丝 56原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值