Android精讲--概述

Android平台架构和特性


Android系统的底层建立在Linux系统之上,该平台由操作系统中间件用户界面应用软件4层组成,它采用一种被称为软件叠层(Software Stack)的方式进行构建。这种软件叠层结构使得层与层之间相互分离,明确各层的分工。这种分工保证了层与层之间的低耦合,当下层的层内或层下发生改变时,上层应用程序无须任何改变。

Android精讲--概述_第1张图片
图1.1 Android系统的体系结构

从图1.1可看出, Android系统主要由5部分组成,下面分别对这5部分进行简单介绍:
1. 应用程序层
Android系统将会包含系列的核心应用程序,包括电子邮件客户端、SMS程序、日历、地图、浏览器。联系人等。这些应用程序都是用Java编写的。
2. 应用程序架构
当我们开发Android应用程序时,就是面向底层的应用程序框架进行的。从这个意义上来看,Android系统上的应用程序时完全平等的,不管是Android系统提供的程序,还是普通开发者提供的程序,都可以访问Android提供的API框架。
应用程序框架除可作为应用程序开发的基础之外,也是软件复用的重要手段,任何一个应用程序都可发布它的功能模块——只要发布时遵守了框架的约定,那么其他应用程序也可以使用这个功能模块。
3. 函数库
Android包含一套被不同组件所使用的C/C++库的集合。一般来说,Android应用开发者不能直接调用这套C/C++库集,但可以通过它上面的应用程序框架来调用这些库。
下面列出一些核心库:

  • 系统C库:一个从BSD系统派生出来的标准C系统库(libc),并且专门为嵌入式Linux设备调整过。
  • 媒体库:基于PacketVideoOpenCORE,这套媒体库支持播放和录制许多流行的音频和视频格式,以及查看静态图片。主要包括MPEG4H.264MP3AACAMRJPGPNG等多媒体格式。
  • Surface Manager:管理对显示子系统的访问,并可以对多个应用程序的2D3D图层机提供无缝整合。
  • LibWebCore:一个全新的Web浏览器引擎,该引擎为Android浏览器提供支持,也为WebView提供支持,WebView完全可以嵌入开发者自己的应用程序中。
  • SGL:底层的2D图形引擎。
  • 3D libraries:基于OpenGL ES 1.0 API实现的3D系统,这套3D库既可使用硬件3D加速(如果硬件系统支持), 也可使用高度优化的软件3D加速。
  • FreeType:位图和向量字体显示。
  • SQLite:供所有应用程序使用的、功能强大的轻量级关系数据库。

4. Android运行时
Android运行时由两部分组成:Android核心库集和Dalvik虚拟机。其中核心库集提供了Java语言核心库所能使用的绝大部分功能,而虚拟机则负责运行Android应用程序。
每个Android应用程序都运行在单独的Dalvik虚拟机内(即每个Android应用程序对应一条Dalvik进程),Dalvik专门针对同时高效地运行多个虚拟机进行了优化,因此Android系统以方便地实现对应用程序进行隔离。
由于Android应用程序的编程语言是Java,因此有些人会把Dalvik虚拟机JVM搞混,但实际上二者存在区别:Dalvik并未完全遵守JVM规范,两者也不兼容。实际上,JVM虚拟机运行的是Java字节码(通常就是.class文件),但Dalvik运行的是其专有的dexDalvik Executable)文件。JVM直接从.class文件JAR包中加载字节码然后运行;而Dalvik则无法直接从.class文件JAR包中加载字节码,它需要通过DX工具将应用程序的所有.class文件编译成.dex文件Dalvik则运行该.dev文件
Dalvik虚拟机非常适合在移动终端上使用,相对于在PC或服务器上运行的虚拟机而言,Dalvik虚拟机不需要很快的CPU计算速度和大量的内存空间,它主要有如下两个特点:

  • 运行专有的.dev文件。专有的.dev文件减少了.class文件中的冗余信息,而且会把所有.class文件整合到一个文件中,从而提高运行性能;而且DX工具还会对.dex文件进行一些性能的优化。
  • 基于寄存器实现。大多数虚拟机(包括JVM)都是基于栈的,而Davlik虚拟机则是基于寄存器的。一般来说,基于寄存器的虚拟机具有更好的性能表现,但在硬件通用性上略差。

Dalvik虚拟机依赖于Linux内核提供的核心功能,如线程和底层内存管理。

5. Linux内核
Android系统建立在Linux 2.6之上。Linux内核提供了安全性内存管理进程管理网络协议栈驱动模型等核心系统服务。此外,Linux内核也是系统硬件和软件叠层之间的抽象层。

Android常用的开发工具


Android开发编译器现在最流行的是Android Studio,现在用Eclipse的开发者已经很少了。高效地开发者要善于利用工具,而且是好的高效地工具。笔者喜欢JetBrains公司的系列产品,现在流行的Java IDE就是该公司开发的IntelliJ IDEA, 而Android Studio是基于IntelliJ IDEA的,是GoogleJetBrains公司合作的项目。开发J2EE服务器端项目我用的就是IntelliJ IDEA。Web前端开发我喜欢用Webstorm,也是JetBrains公司的产品。

# Android模拟器
最理想的开发环境当然是用手机真机,但一般个人甚至单位都不会提供现在市面上所有品牌、所有尺寸、所有版本的手机来开发测试,这不现实。所以Android模拟器emulator对开发的适配工作就非常有帮助,能够在电脑上直接模拟各种手机机型的运行环境。

# 使用DDMS进行调试
Android提供了一个DDMS(Dalvik Debug Monitor Service)调试环境。不管是Eclipse还是Android Studio,一般都有这些调试面板:设备面板信息输出面板线程跟踪面板Heap内存跟踪面板模拟器控制面板文件管理对话框
关于DDMS的使用,多说无益,读者必须在实践中不断积累。

# 使用ADB
Android Debug Bridge(ADB)是一个功能非常强大的工具,它位于Android SDK安装目录的platform-tools子目录下。ADB工具即可完成模拟器文件与电脑文件的相互复制,也可安装APK应用,甚至可以直接切换到Android系统中执行Linux命令。

# 使用DX编译Android应用
前面已经提到,Android平台有一个重要的概念:Android运行时。Android运行时使用的虚拟机并没有遵循JVM规范,Android所使用的虚拟机是Dalvik虚拟机。
Dalvik虚拟机并不直接运行Java二进制文件,而是运行它特有的*.dex文件,因此我们需要通过DX工具将Android应用的.class文件转换为.dex文件。
DX工具的常见命令格式如下:

dx --dex [--dump-to=] [--core-library] [.class | .{zip,jar,apk} | ]

上面的命令中[--dump-to=]指定生成的*.dex文件的文件名;而--core-library指定需要转换的*.class*.zip*.jar文件或者目录。
例如以下命令:

dx -dex --dump-to=g:\a.dex --core-library d:\helloworld\bin

d:\helloworld\bin路径下所有二进制文件转换为g:\根目录下的a.dex文件。

# 使用AAPT打包资源
开发Android应用时,该应用中可能会包含许多资源文件,包括各种图片、音频文件等。Android Asset Packaging Tool(AAPT)就是用来打包这些资源文件的。其实开发中,IDE已经为我们做好这些工作,打包的命令,以及上一小节的DX编译命令,实际上并不需要我们在命令行执行,在此仅做了解。

# 使用mksdcard管理虚拟SD卡
我们可以在创建AVD设备时创建一个虚拟SD卡。实际上还可以使用mksdcard命令来单独创建一个虚拟存储卡。
mksdcard命令的语法格式如下:

mksdcard [-1 label]  

上面的命令格式中指定虚拟SD卡的大小,指定保存虚拟SD卡的文件镜像。
例如以下命令:

mksdcard 64M D:\avds\.android\avd\henry.avd\sdcard.img

创建一个大小为64MB的虚拟SD卡,该SD卡对应的镜像文件为D:\avds\.android\avd\henry.avd\sdcard.img
实际上,Android Studio提供丰富的用户界面给用户设置虚拟SD卡,这里的命令只有做加深理解的意义。

Android应用结构分析


用Android Studio创建的项目,应用目录结构如图:

Android精讲--概述_第2张图片
android应用结构

关于每一个目录和文件的具体意义和用法,我另写了单独的一节Android应用结构解析

Android基本组件


Android应用通常由一个或多个基本组件组成,android应用中最常用的组件就是Activity。Android应用还可能包括Service、BroacastReceiver、ContentProvider等组件:

  • Activity: 实际上Activity是Window的容器,Activity包含一个getWindow()方法,该方法返回该Activity所包含的窗口。对于Activity而言,开发者一般不需要关心Window对象。如果应用程序不调用Activity的setContentView()来设置该窗口显示的内容,那么该程序将显示一个空窗口。

    View组件是所有UI控件、容器控件的基类,View组件就是Android应用中用户实实在在看到的部分。但View组件需要放到容器组件中,或者使用Activity将它显示出来。如果需要通过某个Activity把指定View显示出来,调用Activity的setContentView()方法即可。

  • Service: Service与Activity的地位是并列的,它也代表一个单独的Android组件。Service与Activity的区别在于:Service通常位于后台运行,它一般不需要与用户交互,因此Service组件没有图形用户界面。

    一个Service组件被运行起来之后,它将拥有自己独立的生命周期,Service组件通常用于为其他组件提供后台服务或监控其他组件的运行状态。

  • BroadcastReceiver: BroadcastReceiver即广播消息接收器,BroadcastReceiver非常类似于事件编程中的监听器。与普通事件监听器不同的是:普通事件监听器的事件源是程序中的对象;而BroadcastReceiver监听的事件源是Android应用中的其他组件。
    当其他组件通过sendBroadcast()、sendStickyBroadcast()或sendOrderedBroadcast()方法发送广播消息时,
    如果该BroadcastReceiver也对该消息“感兴趣”(通过IntentFilter配置),
    BroadcastReceiver的onReceive(Context context, Intent intent)方法将会被触发。
    有2种方式注册这个系统级的“事件监听器”:

  1. 在Java代码中通过Context.registReceiver()方法注册BroadcastReceiver。
  2. 在AndroidManifest.xml文件中使用元素注册。
  • ContentProvider: 对于Android应用程序,它们必须相互独立,各自运行在自己的Dalvik虚拟机实例中,如果这些Android应用程序之间需要实现实时的数据交换。

    Android系统为这种跨应用的数据交换提供了一个标准: ContentProvider。
    当用户实现自己的ContentProvider时,需要实现如下抽象方法:

    insert(Uri, ContentValues): 向ContentProvider插入数据
    delete(Uri, ContentValues): 删除ContentProvider中指定数据
    update(Uri, ContentValues, String, String[]): 更新ContentProvider中指定数据
    query(Uri, String[], String, String[], String): 从ContentProvider查询数据。

    通常与ContentProvider结合使用的是ContentResolver,一个应用程序使用ContentProvider暴露自己的数据,而另一个应用程序则通过ContentResolver来访问数据。

  • Intent和IntentFilter: Intent不是Android应用的组件,但它对于Android应用的作用非常大——它是Android应用内不同组件之间通信的载体。
    当Android运行时需要连接不同的组件时,通常就需要借助于Intent来实现。Intent封装了当前组件需要启动或触发的目标组件的信息。
    Intent可以启动应用中另一个Activity,也可以启动一个Service组件,还可以发送一条广播消息来触发系统中的BroadcastReceiver。
    也就是说,Activity、Service、BroadcastReceiver三种组件之间的通信都以Intent作为载体,只是不同组件使用Intent的机制略有区别而已。

    1. 启动Activity,Context.startActivity(Intent intent)或Context.startActivityForResult(Intent intent, int requestCode)
    2. 启动Service,Context.startService(Intent intent)或Context.bindService(Intent service, ServiceConnection conn, int flags)
    3. 启动BroadcastReceiver. Context.sendBroadcast(Intent intent)、Context.sendStickyBroadcast(Intent intent)或Context.sendOrderedBroadcast(Intent intent, String receiverPermission)
      Intent分为2类:

    显示Intent: 明确指定需要启动或者触发的组件的类名。
    隐式Intent: 指定需要启动或者触发的组件应满足怎样的条件。

    对显示Intent, Android系统无须对该Intent做任何解析,系统直接找到指定的目标组件,启动或触发它。
    对隐式Intent,Android系统需要对该Intent进行解析,解析出它的条件,然后再去系统中查找与之匹配的目标组件。如果找到符合条件的组件,就启动或触发它们。

IntentFilter用来声明满足的条件,从而判断被调用组件是否符合隐式Intent。

Android应用签名


Android项目以它的报名作为唯一标识。如果在同一台手机上安装两个包名相同的应用,后面安装的应用就可以覆盖前面安装的应用。为了避免这种情况发生,Android要求对作为产品发布的应用进行签名。
签名主要有如下两个作用:

确定发布者的身份。由于应用开发者可以通过使用相同包名来替换已经安装的程序,因此使用签名可以避免发生这种情况。
确保应用的完整性。签名会对应用包中的每个文件进行处理,从而确保程序包中的文件不会被替换。

Android应用签名的作用类似于现实生活中的签名。当开发者对Android应用签名时,相当于告诉外界:该应用程序是由”我“开发的,”我“会对该应用负责——因为有签名(签名有密钥),别人无法冒名顶替”我“;与此同时,”我“也无法冒名顶替别人。

注:本节内容整理自《疯狂android讲义》

你可能感兴趣的:(Android精讲--概述)