JNI原理学习,美团Android面试题

1.3 Native方法注册


Native方法注册分为两种:

  • 静态注册

多用于NDK开发

  • 动态注册

多用于Framework层开发

下面我们用实际的例子对两种注册做区分及了解。

1.静态注册

我们在Android Studio一个项目中

右键本项目->new->module->Java Library

LibraryName = media

Java class name = MediaRecorder.java,创建成功后,打开MediaRecorder.class,并学着MediaRecorder编写:

在这里插入图片描述

接着我们对MediaRecorder.java进行编译和生成JNI方法,我们进入 media/src/main/java中,在 terminal命令行中输入:

javac com/rikkatheworld/media/MediaRecorder.java

javah -jni com.rikkatheworld.media.MediaRecorder

最后会产生了一个 MediaReorder.class和一个 com_rikkatheworld_media_MediaRecorder.h头文件。

上面可能这里可能会有点坑,可以看我 Android音视频开发入门(5)使用LAME编码一个PCM文件第一节怎么去搭建一个JNI项目,这里我就不多赘述。

我们来看下这个被编译出来的头文件的内容:

// com_rikkatheworld_media_MediaRecorder.h

#include <jni.h>

#ifndef _Included_com_rikkatheworld_media_MediaRecorder

#define _Included_com_rikkatheworld_media_MediaRecorder

#ifdef __cplusplus

extern “C” {

#endif

// 1

JNIEXPORT void JNICALL Java_com_rikkatheworld_media_MediaRecorder_native_1init

(JNIEnv *, jclass);

JNIEXPORT void JNICALL Java_com_rikkatheworld_media_MediaRecorder_start

(JNIEnv *, jobject);

#ifdef __cplusplus

}

#endif

#endif

被编译出来的头文件就是我们Java层在JNI层中对应的类。

注释1中的方法:以Java开头,说明这个方法在Java中调用JNI方法的,后面的名称是以 包名+类名+方法名组成格式,还发现 native_1init()中多了个“1”,这是因为Java声明的native_init()中有 “_”下划线,转换成到native语言中,就变成了 “_1”。

其中 JNIEnv是Native世界中 Java环境的代表,通过 JNIEnv *这个指针,就可以在Native层中访问Java层的代码并进行操作了,它只在创建它的线程中有效,不能跨线程传递。

jclass是JNI型数据,对应Java的 java.lang.Class的实例,是所有对象的父类。

上面这两个数据类型是JNI层常用且关键的数据,后面会对其做介绍。

我们在 Java层中调用 native_init()后,就会从 JNI中寻找 Java_com_rikkatheworld_media_MediaRecorder_native_1init()的函数,如果没有,就会报错,如果找到就会为这两个方法建立一个关联,它就会保存一个JNI的函数指针,即一个指针指向了这个函数,等下一次再调用这个方法时,这个指针所指向的函数就能立马被调用。这就是静态注册。

静态注册总结:

根据方法名,将Java方法和JNI函数建立联系,它的缺点是:

  • JNI层的函数名非常长,它是 Java+包名+类名+方法名

  • 声明Native方法的类需要用 javah生成头文件

  • 第一次调用时,由于JNI层的指针还未指向对应函数,所以它要一个一个找直到找到,所以每第一次调用新的Native方法时,效率并不会太高

2.动态注册

静态注册是Java的Native通过方法指针来与JNI进行关联的,如果Java的Native方法一开始就知道它在JNI中对应的函数指针,就可以避免上述的缺点,这就是动态注册。

JNI中有一种结构来记录Java的Native方法和JNI方法的关联联系,它就是 JNINativeMethod,它在jni.h中的源码是这样的:

// jni.h

typedef struct {

const char* name; //Java方法中的名字

const char* signature; //Java方法的简明信息

void* fnPtr; //JNI中对应的方法指针

} JNINativeMethod;

我们应用开发中使用的 MediaRecorder就是采用动态注册的方式,我们来看看其JNI层是怎么来使用这个 JNINativeMethod的:

// android_media_MediaRecorder.cpp

static const JNIN

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android JNI学习路线可以按照以下步骤进行: 1. 了解JNI的基本概念和作用:JNI(Java Native Interface)是Java提供的一种机制,用于实现Java与其他编程语言(如C、C++)之间的交互。它允许在Java代码中调用本地代码(Native Code),并且可以在本地代码中调用Java代码。 2. 学习JNI的基本语法和规则:JNI使用一组特定的函数和数据类型来实现Java与本地代码之间的交互。你需要学习如何声明本地方法、如何在Java代码中调用本地方法、如何在本地代码中调用Java方法等。 3. 学习JNI的数据类型映射:JNI提供了一套数据类型映射规则,用于将Java数据类型映射到本地代码中的数据类型。你需要学习如何处理基本数据类型、对象类型、数组类型等。 4. 学习JNI的异常处理:在JNI中,Java代码和本地代码之间的异常处理是非常重要的。你需要学习如何在本地代码中抛出异常、如何在Java代码中捕获异常等。 5. 学习JNI的线程处理:JNI允许在本地代码中创建和操作线程。你需要学习如何创建和销毁线程、如何在线程之间进行通信等。 6. 学习JNI的性能优化:JNI涉及到Java代码和本地代码之间的频繁切换,因此性能优化是非常重要的。你需要学习如何减少JNI调用的次数、如何避免不必要的数据拷贝等。 7. 学习JNI的调试和测试:在开发JNI程序时,调试和测试是非常重要的。你需要学习如何使用调试器调试本地代码、如何进行单元测试等。 8. 学习JNI的进阶主题:一旦掌握了基本的JNI知识,你可以进一步学习JNI的进阶主题,如JNI与Java虚拟机的交互、JNI与动态链接库的交互、JNI与多线程的交互等。 总结起来,Android JNI学习路线包括了基本概念、基本语法、数据类型映射、异常处理、线程处理、性能优化、调试和测试以及进阶主题等内容。通过系统地学习这些知识,你将能够更好地理解和应用JNI技术。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值