深入理解Android(02)——深入理解JNI与应用

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层抛出异常。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值