JNI与NDK开发(二)——JNI基本概念 与 Java对C或C++函数的简单调用

JNI与NDK开发(一)——项目初建 我们介绍了一下,JNI(也是NDK开发)环境的搭建步骤,并创建了JNI的Hello World项目。也大体介绍了JNI调用的基本步骤和代码结构。
这一篇,我们将具体介绍一下JNI的一些基本概念,更深的理解JNI的运作过程。在文章的末尾,将介绍JNI调用C的,一种简单的实际步骤(当然,下一章节介绍比较复杂也较为正规的实现步骤)和语法规则。

在这里插入图片描述
上图,是上一篇 JNI与NDK开发(一)——项目初建 cpp文件加下的 Native方法的截图。仔细观察可以发现,这个函数执行的逻辑过程中并不需要任何参数。但是参数部分却有 JNIEnv 和 jobject两个参数存在。而且,以后的Nativie函数(方法)第一个参数永远是JNIEnv指针,而第二个参数永远是jobject或jclass中的一个。
注:1、 JNIEnv *env: 这个参数就是用于调用Java

JNI中最为关键的基本概念有三个:

1、JNIEnv :Java本地接口环境(Java Native Interface Environment)。

具体解释:它JNI接口指针。作用是:指向了本地方法的一个函数表,该函数表中的每一个成员会对应指向了一个JNI函数。所指向的JNI函数,将用来访问JVM中的数据结构。

通俗理解:C或C++ 如果需要访问Java的 对象、类 或方法,就需要通过这个JNIEnv,它里面包含了所有的API。实际开发中,只要涉及C或C++交互Java,均需要使用JNIEnv。

2、JavaVM: Java虚拟机。Java里面原本,一个进程中可以创建很多JavaVM;但在Android中一个进程中只能有一个JavaVM对象(也就是单进程的app,只有一个JavaVM),这个对象是线程共享的。

JavaVM 是用来获取 JNIEnv
通过JNIEnv我们可以获取一个Java虚拟机对象,其函数如下:

jint GetJavaVM(JNIEnv *env, JavaVM **vm);
3、线程:一个 JavaVM 里面有很多线程,每一个Java线程,对应一个JNIEnv。

也就是说,从C层去访问Java的 对象或方法,必须是先获取当前的线程下的JNIEnv才能进行访问。在实际开发中,JNI的Catch,很多情况是由于C与Java交互时,使用的JNIEnv与要访问的Java对象不在同一线程造成的。

C或C++ Native方法结构解析

在这里插入图片描述
①:包名;
②:Class 文件名;
③:Java中的Native方法名;
④:JNIEnv C用于访问Java中对象、类或方法;
⑤:jobject 在Java中谁调用这个Native方法,这里就表示将调用者以对象参数的形式,传递过来以备使用;
jobject 表示通用类型的object,JNI中的表示就是前面加 “j”,也就是 jobject。

JNIEnv 与 jobject 这两个参数,是JavaVM 在调用C或C++接口时传递过来的。
也就是说,Java代码,调用Java 中写的 native方法时,是调用JavaVM。JavaVM 再去调用 它线程下的JNIEnv,JNIEnv指向了本地方法的一个函数表,这个函数表映射了具体要调用的JNI函数。

C里的native函数,有了JNIEnv这个对象env,就可调用Java中的方法。如下:env 调用了一个 Java的对象 NewStringUTF。这里就表示,将C或C++的 字符串,转成Java的对象,再返回到Java中使用。

env->NewStringUTF(hello.c_str());
下面介绍一下Java 中Native 方法带参数的调用

写一个带一个String参数的native方法,将其返回值与 HelloWorld拼接显示输出。
在这里插入图片描述
下图是对应 cpp 文件夹 下的 Native方法(AndroidStudio工具,可以根据Java中 新建Native方法,进行自动创建生成以下方法)。
在这里插入图片描述
①:每个Native方法都必须写的,其中jstring表示的是返回值类型;
②:每个Native方法都必须写的,固有的两个参数;
③:jstring 表示传入的参数类型(后面有Java 与 JNI 数据类型对应表);
④:传入的 str_ 不能直接使用,将jstring转换成为UTF-8格式的char*;
⑤:释放指向UTF-8格式的char*的指针(释放资源在C或C++中非常重要);
⑥:向Java返回被转换为Java对象的 char类型数据;

下图是运行结果:
在这里插入图片描述
总结以上JNI调用的主要步骤:
1、在Java层定义,native关键字的方法;
2、在C/C++层创建,Java_packname_classname_methodname的函数(固定的函数命名格式,JNI自动映射Java对应的native方法)。

附表数据类型对应表:

Java类型JNI类型描述
booleanjbooleanunsigned 8 bits
bytejbytesigned 8 bits
charjcharunsigned 16 bits
shortjshortsigned 16 bits
intjintsigned 32 bits
longjlongsigned 64 bits
floatjfloat32 bits
doublejdouble64 bits
voidvoidvoid

以上是JNI的基本调用方法,应该很简单(当然只是基本调用)。其实在Android 和 JNI推荐了另一种更好的调用方式,期待下一篇博客能有时间写清楚吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值