Android 进阶——NDK开发

来源:互联网 发布:城乡居民收入差距数据 编辑:程序博客网 时间:2024/06/05 11:17
  • NDK介绍

    NDK(Native Development Kit)即本地代码开发套件,既然提到本地代码与之对应就有非本地代码。
    众所周知Android系统是基于Linux进行改写而成,而Android程序是由Java代码进行编写,Java代码最大的优点在于其跨平台的特性,因此不能直接运行在操作系统之上,而是运行在自家的JVM虚拟机中,Android程序也是这样,每一个Android程序都运行在一个独立的Dalvik虚拟机中。
    由于这个机制当系统需要执行对应的Java代码时Dalvik虚拟机会进行一次解释,这样便导致了运行速率的降低。所以便引入了本地代码native的概念,使用本地代码编写程序可以由操作系统直接执行,省去了中间虚拟机解释的过程,可以让应用运行的更快。而NDK就是Google公司开发的一套可以将C代码编译成本地代码的开发套件。

  • 使用NDK的好处
    1. 可以提高程序的执行效率。
    2. 常见的.class很容易被反编译,而C/C++库被反编译的难度较大。
    3. C语言的历史显然远远大于Java,因此市面上存在大量现成的C/C++库可以提供使用。
    4. C语言库支持各种硬件平台,因此编写C库可以方便在别的平台进行复用,例如嵌入式开发。
    5. 支持增量升级。
  • JNI
    JNI(Java Native Interface)即Java本地接口,熟悉Java和面向对象的人都知道接口的含义,简而言之就是一种规则、规范。这里的JNI也是同样的道理。
    在Android中编写本地代码需要使用C/C++进行编程,而如何定义Java和C两种不同语言的交互规则就是JNI的存在意义。可以将JNI看做一座桥梁,一座连通Java和C的桥梁,两种语言需要通过JNI这座桥才可以进行信息的交换。直接的体现就是通过JNI可以将Java的数据给C使用,同时C的数据也能给Java使用。
    常见的例子:Java需要使用一串字符串时,有封装好的String对象,而在C语言中是没有String这种概念的,字符串在C中只能通过*char[]字符数组的指针进行操作,为了实现两种平台的交互,JNI中定义了jstring的类型。

  • 链接库

    • 静态链接库
      将所需要的一切依赖库都便已在一个文件中,体积大。后缀名.a
    • 动态链接库
      运行时才去查找相关依赖库,体积小,但是可能出现找不到依赖库等问题。
  • 交叉编译
    在某个平台上生成另一个平台的可执行代码
    例如:x86 -> Arm Arm->x86

  • make
    将指定的C文件编译成可执行的链接库

Android下本地开发基本流程

1.创建java类,声明需要使用的本地方法,用native标识。
2. 通过JDK命令javah生成本地方法对应的c头文件。
3. 编写JNI层,引入生成的头文件,并且实现其中的方法。
4. 编写CMakeLists.txt(老版本为Android.mk已经被cmake代替)文件,引入三方链接库,头文件,以及之间的关联关系。设置最终编译的链接库名字和类型。
5. 在Java代码中使用静态代码块引入,其中名字为make文件中设置的名字,不需要写后缀名。(最后生成的名字和设置的名字会有所不同,通常会在前面默认添加lib

{System.loadLibrary("xxxx");}

写在最后

远在Android2.2之后Google便引入了JIT(Just In Time Compiler)编译系统。我们使用Java开发android,在编译打包APK文件时,会经过以下流程:

  1. Java编译器将应用中所有Java文件编译为class文件
  2. dx工具将应用编译输出的类文件转换为Dalvik字节码,即dex文件之后经过签名、对齐等操作变为APK文件。

Dalvik虚拟机可以看做是一个Java VM,他负责解释dex文件为机器码,如果我们不做处理的话,每次执行代码,都需要Dalvik将dex代码翻译为微处理器指令,然后交给系统处理,这样效率不高。

为了解决这个问题,Google在2.2版本添加了JIT编译器,当App运行时,每当遇到一个新类,JIT编译器就会对这个类进行编译,经过编译后的代码,会被优化成相当精简的本地代码(即native code),这样就避免了虚拟机解释的过程。
一直持续到Android4.4之后,Google公司提出了另外一套运行模式ART(Android Run Time)。

JIT编译方式虽然实现了每次运行程序只需要执行一次编译工作,但是依然运行在虚拟机上,编译工作是及时性进行的,也就是每次运行程序后都需要再次对代码进行编译。

ART的策略与Dalvik不同,在ART 环境中,应用在第一次安装的时候,字节码就会预先编译成机器码,使其成为真正的本地应用。之后打开App的时候,不需要额外的翻译工作,直接使用本地机器码运行,因此运行速度提高。

通过ART和JIT,其实现在使用Java编写的Android程序相对于C已经不存在明显的劣势了,那为什么我们还要使用NDK开发呢。个人分析,有以下几点:

  1. 虽然从编译角度上说两者几乎已经没有区别,但是Java的特性决定了对于一些大量精密的逻辑操作远不如C来的简单粗暴,毕竟C中的静态内存是程序员自己分配和释放的,可以在使用代码使用完后的第一时间进行资源的释放,而Java则是依赖GC进行自动的垃圾回收,虽然GC的算法很强大,但是灵活性始终不如人工来的即时。
  2. C语言历史悠久,为了使用已有的解决方案无法避免的需要调用他人封装好的C库。
  3. 对于一些底层开发,如硬件层和协议层,C可以直接操作内存地址和CPU指令的特点无可替代。

因此我们需要理性分析,根据实际情况酌情使用NDK开发。并不是NDK效率就一定会高于原生Java开发。

0 0
原创粉丝点击