1、JNI概述
JNI(Java Native Interface)Java本地调用接口。JNI主要实现两个目标:
(1)Java程序中的函数,可以调用native编写的函数方法,一般是指C或者C++语言写的代码
(2)Native中的函数可以调用Java中的方法和函数
JNI主要解决两个问题:
(1)解决了Java的平台无关性,这一点是通过底层的Native代码来实现的
(2)Java中不能实现的高性能,需要使用到Native代码参与支持。
2、实例:MediaScanner
MediaScanner是Android平台上多媒体系统的重要组成部分,它的主要作用是扫描媒体文件,得到媒体文件的具体信息,比如歌曲名字,作者信息,时间长短等等,并将之存储在媒体数据库中,以供其它程序使用。
MediaScanner大概分为三个部分,分别对应的文件信息如下:
JAVA(MediaScanner.java)JNI(libmedia_jni.so)
Native(libmedia.so)
MediaScanner将通过JNI库libmedia_jin.so和Native层的libmedia.so交互。
3、Java层代码分析
MediaScanner.java文件代码抽出如下:
public class MediaScanner
{
static {
System.loadLibrary("media_jni");
native_init();
}
public MediaScanner(Context c) {
native_setup();
mContext = c;
mBitmapOptions.inSampleSize = 1;
mBitmapOptions.inJustDecodeBounds = true;
setDefaultRingtoneFileNames();
}
public native void setLocale(String locale);
public void scanDirectories(String[] directories, String volumeName) {
//......
}
// ......
}
本段代码列出了两个比较重要的要点:(1)加载JNI库文件;(2)Java的Native函数。
4、JNI层的MediaScanner
一段初始化的操作:
static void android_media_MediaScanner_native_init(JNIEnv *env)
{
jclass clazz;
clazz = env->FindClass("android/media/MediaScanner");
if (clazz == NULL) {
jniThrowException(env, "java/lang/RuntimeException", "Can't find android/media/MediaScanner");
return;
}
fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
if (fields.context == NULL) {
jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaScanner.mNativeContext");
return;
}
}
5、JNI函数对应
很多人会很奇怪,为什么在Java层调用的native_init()就是在JNI层的android_media_MediaScanner_native_init()函数呢?是不是有对应的法则?
答案是有的,在Java代码中,native_init()这个函数位于android.media这个包下面,所以对应的,在JNI中就成为了android_media_MediaScanner_native_init()。如果我们的包名为com.google.android.media,那么我们对应的JNI函数应该为:com_google_android_media_MediaScanner_native_init()。
可能大家会奇怪为什么不使用Java中一样的命名方式,而是是使用下划线?因为“.”这个字符在Native语言中,有比较特殊的含义,所以避免冲突,使用“_”作为分隔标识。
6、JNI数据转换
在我的博客分类中,应该有介绍过JNI与java交互中的数据转换,这里再次发一个对应图示说明:
JNI数据转换
详细的解说,大家可以去看我另外的一篇博客中的介绍,有专门对JNI的数据类型进行过说明。
JNI数据类型在C中的映射地址:http://blog.csdn.net/ljtyzhr/article/details/39961913
7、JNI异常处理
JNI中也会有一些异常信息,但是JNI中的异常与C中的异常不一样。如果调用JNIEnv的某些函数出错了,则会产生一个异常,但这个异常不会中断本地函数的执行,直到从JNI层返回到Java层之后,虚拟机才会抛出这个异常。
虽然在JNI中不会中断本地函数的运行,但是产生异常之后,就会做一些清理工作。JNI中提供了以下三个函数处理异常信息:
1)ExceptionOccured函数,用来判断是否发生异常;
2)ExceptionClead函数,用来清理当前JNI层中发生的异常;
3)ThrowNew函数,用来向Java层抛出异常。