深入理解Android(2)__深入理解JNI

前言:前面一贴,我们大概了解了Android系统的架构,对于每个层次的东东也有了基本的了解,那么我们就可以正式动工,开始逐个突破,攻克每一个难点,你有没有很激动?OK,下面我们就拿JNI来练练手。

  JNI:Java NativeInterface(Java本地调用),说的简单点,JNI就是一种技术,它是干什么的?主要有两点:

    (1)Java程序中的函数可以调用Native语言写的函数,Native一般就是指C/C++编写的函数;

    (2)Native程序中的函数可以调用Java层的函数。

  看到这个,大家怎么想?其实,我们可以把JNI当作一个桥梁,连接着Java层与Native层。

                                                            

  虽然JNI是用Native编写的,但是我们依然把它归类于一个单独的层:JNI层。

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

  1、JNI实例:MediaScanner(结合层次图进行分析)---多媒体系统的重要组成部分,功能是扫描媒体文件,得到诸如歌曲时长、歌曲作者等媒体信息,并将它们存入到媒体数据库中。

    (1)Java世界对应的是MediaScanner,MediaScanner这个类有一些函数是需要Native层来实现的;

    (2)JNI对应的是libmedia_jni.so,media_jni是JNI库的名称。其中_线前的media是native层库的名字,这里就是libmedia库。_线后的jni代表它是一个JNI库。JNI库的名称可以随便取,但是遵循以下命名规则:"lib模块名_jni.so";

    (3)Native对应的是libmedia.so,这个库完成了实际的功能;

    (4)Java层将通过JNI库的libmedia_jni.so与Native库的libmedia.so交互。

  我们先来看看与JNI有关的代码:

 1 public class MediaScanner
 2 {
 3        static{
 4             System.loadLibrary("media_jni");  //加载对应的JNI库
 5             native_init();  //调用native函数
 6     }
 7     ......
 8     //非native函数
 9     public void scanDirectories(String[] directories, String volumeName)
10     {
11     ......
12     }
13     private static native final void native_init();     //申明一个native函数,native为Java关键字,表示它将由JNI层完成。
14     ......
15     private native void processFile(String path, String mimeType, MediaScannerClient client);
16     ......
17 }

  以上的代码列出了两个比较重要的点:

  (1)加载JNI库:要调用Native,就必须通过一个位于JNI层的动态库来实现,一般是在类的static语句中加载,方式是:System.loadLibrary,加载动态库的名字后,系统会自动根据不同的平台拓展成真实的动态库文件名,例如:在Linux中会拓展成libmedia_jni.so,而在windows平台上则会拓展成media_jni.dll

  (2)Java的native函数:我们发现在native_init和processFile函数前都有native关键字,它表示这两个函数将由JNI层来实现。

  所以,你如果要想使用JNI,只要完成以上两项工作。不过JNI要完成任务,可是比较复杂的,下面我们会一起分析。

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

  2、JNI层MediaScanner分析

    由于时间的问题,部分JNI层代码用图片的形式表示。

         

  此时,我相信你可能会产生疑惑:如何才能知道Java层的native_init函数对应的是JNI层的android_media_MediaScanner_native_init函数呢?

  (1)注册JNI函数

  大家知道,native_init函数位于android.media包中,它的全路径名称是:android.media.MediaScanner.native_init,而JNI层函数的名字是android_media_MediaScanner_native_init。

  有没有发现问题?好了,我直接告诉你把:在Native语言中,符号 “.” 是有着特殊含义的,所以JNI层需要把Java函数名称(包括包名) 中的 “.” 换成 “ _ ”,也就是通过这种方式,native_init找到了自己JNI层的本家兄弟android_media_MediaScanner_native_init的。

  其实上面,我们讨论的就是一个“注册”的问题。“注册”就是:将Java层的native函数和JNI层对应的实现函数关联起来。有了这种关联,调用Java层的native函数事,就能顺利转到JNI层对应的函数执行了。

  “注册”有两种方式:(对于关联的具体不过代码不作分析,我们大概了解注册的原理即可,如果感兴趣的同学,可以给我回复,有必要的话,我会专门写一个帖子讲解一下)

    · 静态注册:就是根据函数名来建立Java函数和JNI函数之间的关联关系(其实就是保存了JNI层函数的函数指针),而且它要求JNI层函数的名字必须遵循特定的格式。

    · 动态注册:如果我们专门使用一个结构(JNINativeMethod)来保存这种关联关系,这样我们就可以直接让native函数知道JNI层对应函数的函数指针,这样的话,是不是提高了效率呢?答案是肯定的!

  我们直接给出答案:当Java层通过System.loadLibrary加载完JNI动态库后,紧接着会查找该库中一个叫JNI_Onload的函数(此函数在android_media_MediaPlayer.cpp中)。如果有,就调用它。而动态注册的工作就是在这里完成的。

  (2)数据类型转换问题

  在Java中调用native函数,传递的参数是Java数据类型,那么这些参数传递到JNI层会变成什么?

  我们知道,Java的数据类型分为两种:基本数据类型引用数据类型

  对于这两个类型,JNI也是区分对待的,下面我们一起来看看:

    ·  基本数据类型的转换

        

      需要注意一下字长的变化,比如jchar的字长为16位,占两个字节,这与普通的char占一个字节是不一样的。

    ·  引用数据类型的转换

        

  (3)JNIEnv介绍

        

    我们来分析以下JNI层函数的5个参数:后面三个参数,大家应该都比较清楚,它们对应Java中的native函数3个参数,那么另外两个参数是什么含义呢?

    我们先来看一下jobject:代表Java层的MediaScanner对象,它表示在哪个MediaScanner对象上调用的processFile。如果Java层是static函数,那么这个参数将是jclass,表示是在调用哪个Java Class的静态函数。

    下面,我们正式引出主角:JNIEnv

    JNIEnv:是一个与线程相关的代表JNI环境的结构体。

    内部结构:

              

    JNIEnv实际上就是提供了一些JNI系统函数,通过这些函数可以做到:

    1、调用Java的函数;2、操作jobject对象等很多事情

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

  在下一个帖子,我们将一起来看看如何使用JNIEnv的函数,并且会跟大家介绍一个关于JNIEnv的重要知识点。

  

时间: 2024-11-05 08:35:42

深入理解Android(2)__深入理解JNI的相关文章

深入理解Android(4)——理解Android中的JNI(下)

在前面文章中简单介绍了JNI,这一篇文章来简单看一下jni.h中定义的一些常用方法,来实现通过C++调用Android中的Java代码. 转载请说明出处:http://blog.csdn.net/dawanganban 一.两个参数的介绍 在前面的代码中我们会遇到两个参数,下面对这两个参数做一解释 1.JNIEnv是指向可用JNI函数表的接口指针,C代码中JNIEnv是指向JNINativeInterface结构的指针,在C语言中JNIEnv必须作为第一个参数传入每一个JNI函数的调用者,如:

深入理解Android(2)——理解Android中的JNI(中)

阳光小强参加了CSDN博客之星评选,如果你觉得阳光小强的博客对你有所帮助,为小强投上一票吧:http://vote.blog.csdn.net/blogstar2014/details?username=lxq_xsyu#content 在上一篇中我们了解了Android中有关JNI的使用,其实JNI是很早就有的,不是在Android创造的新技术,是SUN为我们提供的一种Java和本地代码之间相互调用的方法,这一篇我们来建立一个普通的Java工程来具体看一下Java中如何调用C/C++代码. 一

深入理解Android(1)——理解Android中的JNI

我参加了CSDN博客之星评选,如果在过去的一段时间里阳光小强的博客对你有所帮助,在这里希望能投上您宝贵的一票,每天都可以投一次:http://vote.blog.csdn.net/blogstar2014/details?username=lxq_xsyu#content 一.什么是JNI JNI是Java Native Interface的缩写(Java本地调用),Java程序中的函数可以调用Native语言写的函数(一般指的是C/C++编写的函数),Native语言写的函数可以调用Java层

深入理解Android(3)__注册JNI函数(详细)

提示: 我们在深入理解Android(2)中简单介绍了JNI函数的注册方式,主要分为:静态注册和动态注册. 思来想去,还是觉得应该对两种注册方式的具体过程,给各位读者做个详细介绍,这样也可以自己做一遍Review,加深以下印象. 下面,我们步入正题,分析以下两种注册方式. -----------------------------------------------------------------------------------------------------------------

[深入理解Android卷一 全文-第二章]深入理解JNI

由于<深入理解Android 卷一>和<深入理解Android卷二>不再出版,而知识的传播不应该因为纸质媒介的问题而中断,所以我将在CSDN博客中全文转发这两本书的全部内容. (出版社排版好的PDF版正在向出版社申请,到时候会通过CSDN下载资源发布) 第2章  深入理解JNI 本章主要内容 ·  通过一个实例,介绍JNI技术和在使用中应注意的问题. 本章涉及的源代码文件名及位置 下面是本章分析的源码文件名及其位置. ·  MediaScanner.java framework/b

深入理解Android(1)__系统架构

最近一直在为Android的系统级开发发愁,很多东西云里雾里,还是觉得是基础知识不够扎实的缘故,所以,思考再三,还是决定认真研读一下<深入理解Android卷I.II>,最近深入手了一本<深入理解Android卷III>,希望能够在研读的过程中,将心得笔记写下,与Android爱好者一起学习,共同进步. 下面我们就进入正题吧. ------------------------------------------------------------------------------

理解Android虚拟机体系结构

1 什么是Dalvik虚拟机 Dalvik是Google公司自己设计用于Android平台的Java虚拟机,它是Android平台的重要组成部分,支持dex格式(Dalvik Executable)的Java应用程序的运行.dex格式是专门为Dalvik设计的一种压缩格式,适合内存和处理器速度有限的系统.Google对其进行了特定的优化,使得Dalvik具有高效.简洁.节省资源的特点.从Android系统架构图知,Dalvik虚拟机运行在Android的运行时库层. 2 Dalvik虚拟机的功能

《深入理解Android 卷III》第五章 深入理解Android输入系统

<深入理解Android 卷III>即将公布.作者是张大伟.此书填补了深入理解Android Framework卷中的一个主要空白.即Android Framework中和UI相关的部分.在一个特别讲究颜值的时代,本书分析了Android 4.2中WindowManagerService.ViewRoot.Input系统.StatusBar.Wallpaper等重要"颜值绘制/处理"模块 第5章 深入理解Android输入系统(节选) 本章主要内容: ·  研究输入事件从设

[深入理解Android卷一全文-第八章]深入理解Surface系统

由于<深入理解Android 卷一>和<深入理解Android卷二>不再出版.而知识的传播不应该由于纸质媒介的问题而中断,所以我将在CSDN博客中全文转发这两本书的全部内容. 第8章  深入理解Surface系统 本章主要内容 ·  具体分析一个Activity的显示过程. ·  具体分析Surface. ·  具体分析SurfaceFlinger. 本章涉及的源代码文件名称及位置: · ActivityThread.java framework/base/core/java/an

深入理解Android之Gradle

深入理解Android之Gradle 格式更加精美的PDF版请到:http://vdisk.weibo.com/s/z68f8l0xTYrZt 下载 Gradle是当前非常"劲爆"得构建工具.本篇文章就是专为讲解Gradle而来.介绍Gradle之前,先说点题外话. 一.题外话 说实话,我在大法工作的时候,就见过Gradle.但是当时我一直不知道这是什么东西.而且大法工具组的工程师还将其和Android Studio大法版一起推送,偶一看就更没兴趣了.为什么那个时候如此不待见Gradl