前言
JNI不仅仅在NDK开发中应用,它更是Android系统中Java与Native交互的桥梁,不理解JNI的话,你就只能停留在Java Framework层。这一个系列我们来一起深入学习JNI。
1.JNI概述
Android系统按语言来划分的话由两个世界组成,分别是Java世界和Native世界。那为什么要这么划分呢?Android系统由Java写不好吗?除了性能的之外,最主要的原因就是在Java诞生之前,就有很多程序和库都是由Native语言写的,因此,重复利用这些Native语言编写的库是十分必要的,况且Native语言编写的库具有更好的性能。
这样就产生了一个问题,Java世界的代码要怎么使用Native世界的代码呢,这就需要一个桥梁来将它们连接在一起,而JNI就是这个桥梁。
通过JNI,Java世界的代码就可以访问Native世界的代码,同样的,Native世界的代码也可以访问Java世界的代码。
为了讲解JNI我们需要分析系统的源码,在即将出版的《Android进阶之光》的最后一章中我拿MediaPlayer框架做了举例,这里换MediaRecorder框架来举例,它和MediaPlayer框架的调用过程十分类似。
2.MediaRecorder框架概述
MediaRecorder我们应该都不陌生,它用于录音和录像。这里不会主要介绍MediaRecorder框架,而是MediaRecorder框架中的JNI。
Java世界对应的是MediaRecorder.java,也就是我们应用开发中直接调用的类。JNI层对用的是libmedia_jni.so,它是一个JNI的动态库。Native层对应的是libmedia.so,这个动态库完成了实际的调用的功能。
3.Java层的MediaRecorder
我们先来查看MediaRecorder.java的源码,截取部分和JNI有关的部分如下所示。
frameworks/base/media/java/android/media/MediaRecorder.java
public class MediaRecorder{
static {
System.loadLibrary("media_jni");//1
native_init();//2
}
...
private static native final void native_init();//3
...
public native void start() throws IllegalStateException;
...
}
在静态代码块中首先调用了注释1处的代码,用来加载名为“media_jni“的动态库,也就是libmedia_jni.so。接着调用注释2处的native_init方法,注释3处的native_init方法用native来修饰,说明它是一个native方法,表示由JNI来实现。MediaRecorder的start方法同样也是一个native方法。
对于Java层来说只需要加载对应的JNI库,接着声明native方法就可以了,剩下的工作由JNI层来完成。
4.JNI层的MediaRecorder
MediaRecorder的JNI层由android_media_recorder.cpp实现,native方法native_init和start的JNI层实现如下所示。
frameworks/base/media/jni/android_media_MediaRecorder.cpp
static