Android 系统概要 ——《第一行代码 Android》

《第一行代码 Android》作为Android入门书籍,由郭霖大神编写的,这本书相对比其他入门书籍比较基础并且深度也不错。本文主要是针对第一章概况读书简记,便于日后温故,总结。

Android 系统起源

首先,作为一名Android开发人员来说,对于Android系统怎么而来的,想必大家或多或少听说一些。Android作为现如今拥有用户群体的手机系统,起初是由Andy Rubin(“Android之父”)同其他三位创始人成立了“Android公司“,为了数码相机开发出来的一套基于Linux系统,这便是Android的雏形。

随后,Android转而开发手机操作系统,并于2005年被谷歌收购,Rubin和其他创始人留在谷歌,开始了真正意义上的智能手机操作系统开发。在这个时候,Android系统的方向已经确定,比如基于Linux、开源、免费供手机厂商使用等等,谷歌则可将其服务深度集成到系统中获得利润。

2008年,谷歌发布了第一版Android系统”Android 1.0“,接着在2009年发布了1.1版本,随后在1.5版本开始出现以甜点命名版本,具体版本如下:

Android Beta,发布于2007年11月5日,同时的软件开发套件(SDK),发布于2007年11月12日。 11月5日被认为是Android的"生日"。

Android版本名称Code name Android版本 版本发布时间 对应API
(no code name) 1.0 2008年9月23日 API level 1
(no code name) 1.1 2009年2月2日 API level 2
Cupcake 1.5 2009年4月17日 API level 3,NDK 1
Donut 1.6 2009年9月15日 API level 4,NDK 2
Eclair 2.0.1 2009年12月3日 API level 6
Eclair 2.1 2010年1月12日 API level 7,NDK3
Froyo 2.2.x 2010年1月12日 API level 8,NDK 4
Gingerbread 2.3 – 2.3.2 2011年1月1日 API level 9,NDK5
Gingerbread 2.3.3 – 2.3.7 2011年9月2日 API level 10
Honeycomb 3.0 2011年2月24日 API level 11
Honeycomb 3.1 2011年5月10日 API level 12,NDK 6
Honeycomb 3.2.x 2011年7月15日 API level 13
Ice Cream Sandwich 4.0.1 – 4.0.2 2011年10月19日 API level 14,NDK 7
Ice Cream Sandwich 4.0.3 – 4.0.4 2012年2月6日 API level 15,NDK 8
Jelly Bean 4.1 2012年6月28日 API level 16
Jelly Bean 4.1.1 2012年6月28日 API level 16
Jelly Bean 4.2-4.2.2 2012年11月 API level 17
Jelly Bean 4.3 2013年7月 API level 18
KitKat 4.4 2013年7月24日 API level 19
Kitkat Watch 4.4W 2014年6月 API level 20
Lollipop(Android L) 5.0/5.1 2014年6月25日 API level 21/API level 22
Marshmallow(Android M) 6.0 2015年5月28日 API level 23
Nougat(Android N) 7.0 2016年5月18日 API level 24
Nougat(Android N) 7.1 2016年12月 API level 25
Oreo(Android O) 8.0 2017年8月22日 API level 26
Oreo(Android O) 8.1 2017年12月5日 API level 27
Pie (Android P)不是凤梨酥(PineappleCake) 9.0 2018年8月7日 API level 28

Android的版本,有个API Level,对应着某个Android发布版本的名称。

Android系统架构

上面我们大概了解了Android的起源以及对应的版本,并且也大概知道Android是基于Linux系统开发出来的移动终端系统,那接下来我们来了解下Android系统的内部架构,Android大致可以分为四层架构:Linux内核层系统运行库层应用框架层应用层

  • Linux内核层:
    Android系统基于Linux内核,这一层为Android设备的各种硬件提供了底层的去驱动,如显卡驱动、音频驱动、相机驱动、蓝牙驱动、WIFI驱动、电源管理等。

  • 系统运行库层:
    这层通过一些C/C++库为Android系统提供了主要的特性支持,例如SQLite库提供了数据库的支持,OpenGL|ES库提供了3D绘图的支持,Webkit库提供了浏览器内核的支持等等。
    同样在这一层,还有谷歌为我们提供的Android运行时库,它主要提供了一些核心库,能够允许开发者使用Java语言来编写Android应用。另外,Android运行时库中还包含了Dalvik虚拟机(5.0系统之后改为ART运行环境,这两种环境在本质上有很大的区别,导致Android在运行性能方面更加优越,具体区别在后期会独篇说明,这里不过多阐述),它使得每个Android应用都能运行在独立的进程中,并且拥有自己的虚拟机实例。相对比于Java虚拟机,Android虚拟机是专门为移动设备定制的,它针对手机内存、CPU性能有限等情况做了优化处理。

  • 应用框架层
    这层主要提供了构建应用程序时可能用到的各种API,Android自带的一些核心应用就是使用这些API完成的。

  • 应用层
    所有安装在手机上的应用程序都属于这一层的,比如系统内置的联系人、短信等程序,或者从应用商城上下载下来的应用以及自己开发的程序都属于这层。

Android系统架构可以参考如下图:

Android 系统概要 ——《第一行代码 Android》_第1张图片
Android系统架构

Android开发环境搭建

针对于开发环境搭建,都是每个开发者老生常谈的必要走的一步,这里就不多累赘,只是贴出各个环境下载链接,便于日后查询配置使用。

  • JDK
  • Android Studio(可能部分小伙伴需要墙,也可以访问百度云盘资源)
  • Android SDK一般这块不需要单独下载,谷歌已经将其集成到Android Studio中了,如果小伙伴有需要下载,也可以在 Android Studio上浏览到Command line tools only选择即可。

关于小伙伴在使用Android Studio过程中可能会遇到一些构建常见问题,可以详情了解下我的另外一篇文字《Android Studio 构建常见出错问题汇总》,以及《Android Studioc常用快捷键汇总》,不定时更新哦!

Android Studio目录结构分析

Android在早期开发还是使用Eclipse比较多,但自从2013年官方推出Android Studio(以下简称AS)之后,Android开发更多的倾向于使用AS开发,而且在推出AS之后,官方也相应停止了Eclipse开发Android对应的ADT更新,所以现在大部分都是采用AS开发。在这里有必要扯一下AS目录结构,毕竟两个IDE的编译机制是有所不同的,在Eclipse采用的Ant方式构建编译项目,而在AS中采用的是Gradle。

Eclipse在这我就不过多阐述了,我们要跟紧时代脚步,所以这里主要讲下AS中项目对应目录结构的功能与作用,新建一个项目,可得到如下所示:

Android 系统概要 ——《第一行代码 Android》_第2张图片
Project模式的项目结构
  1. .gradle和.idea
    这两个目录下放置的都是AS自动生成的一些文件,所以这块我们不用关心,在拷贝项目备份或者版本管理时候,可以忽略这两个目录。

  2. app
    项目中的代码、资源等内容几乎都在这个目录下,日常编写代码大部分也都在这个目录下进行的,所以这个目录的文件结构后面会单独解析具体底层目录。

  3. build
    在AS高版本中这个目录已经不存在,低版本中存在这个目录,也是AS编译时自动生成的文件,不用关心,在拷贝项目备份或者文件管理时候,同样是可以忽略的目录。

  4. gradle
    在这个目录下包含了gradle wrapper的配置文件,使用gradle wrapper的方式无需提前将gradle下载好,而是会自动根据本地的缓存情况决定是否需要联网下载gradle。

  5. .gitignore
    这个文件用来将指定的目录或文件排除在版本控制(Git)之外的。

  6. build.gradle
    这个文件是全局的gradle的构建脚本,通常这个文件中的内容是不需要修改的。后面会具有分析gradle构建脚本的内容。

  7. gradle.properties
    这个文件是全局的gradle配置文件,在这里配置的属性会影响到项目中所有的gradle编译脚本。

  8. gradlew 和 gradlew.bat
    这个两个文件是用来在命令行界面(Terminal)中执行gradle命令的,其中gradlew是在Linux或Mac系统中使用的,gradlew.bat是在windows系统中使用的。

  9. HelloWorld.iml
    iml文件是所有IntelliJ IDEA项目都会自动生成的一个文件(AS是基于IntelliJ IDEA开发的),用于标识这是由IntelliJ IDEA项目,不需要修改此文件,可以在备份或者版本控制时候忽略。

  10. local.properties
    文件是用于指定本机中的Android SDK路径,以及NDK路径,通常不需要修改,除非本地环境发生改变时候。

  11. setting.gradle
    这个文件同于指定项目中所有引入的模块,由于此处只有app一个模块,因此该文件这里只引入的app这一个模块。通常情况都是自动完成的,只有手动导入模块时候,可能需要手动去修改。

整个项目的外层结构基本到这有一个大致的了解,接下来说下app目录,也就是我们代码经常需要修改调整的目录下的结构,如下所示:

Android 系统概要 ——《第一行代码 Android》_第3张图片
app目录下的结构
  1. build
    这个目录和外层的build目录相似,主要也是包含了编译自动生成的文件,同样也无需关心,可以备份或者版本控制可以忽略。

  2. libs
    项目中使用第三方jar包,需要把对应的jar包放在这个目录下,放在这个目录下的jar包会被自动添加到构建路径里去。

  3. androidTest
    此处用来编写AndroidTest测试用例的,可以对项目进行一些自动化测试。

  4. java
    此处用于编写应用的主要逻辑Java代码。

  5. res
    这个目录主要存放应用的UI布局字符串等资源,这个目录相对比较复杂,在子目录layout下主要存放应用的布局文件,而图片根据不同的分辨率存放在以drawble-xxx目录下,当然有些类似selector选择器或者Shape自定义形状等等这些还是放在drawble中,子目录values下主要存放字符串、样式以及主题等。
    在这个目录所有子目录下有一个子目录mipmap-xxx需要特别说明以下,mipmap是在Android Jelly Beans 4.3中提出来的,主要是为了让程序能够更好的兼容各种设备,在处理Launcher Icon图片渲染方面更加强大。

  6. AndroidManifest.xml
    这个文件是整个应用的配置文件,在程序中定义的所有四大组件都必须在这个文件里注册,在这个文件配置需要的相应权限配置声明。

  7. test
    此处用来编写Unit Test测试用例的,是对项目进行自动化测试的另外一种方式。

  8. .gitignore
    这个文件用于app模块内的指定的目录或文件的排除在版本控制(Git)之外,作用与外层的.gitignore,但一般都在外层的.gitignore全局设置了。

  9. app.iml
    IntelliJ IDEA项目自动生成的文件,不需要去修改与关心,备份或版本控制时候可以忽略。

  10. build.gradle
    app模块的gradle构建脚本,这个文件会指定很多项目构建相关的配置。

  11. proguard-rules.pro
    这个文件用于指定项目代码的混淆规则,当我们的代码编写打包成apk时候,如果不希望别人破解,通常会将代码进行混淆,从而让破解者难以阅读,考虑安全点,一般还会对apk进行加固。

因为Android Studio是采用Gradle来构建项目的,所以这里对Gradle的配置文件进一步讲解。Gradle是一个非常先进的项目构建工具,它使用了一种基于Groovy的领域特定语言(DSL)来声明项目设置,摒弃了传统基于XML(如Ant和Maven)的各种烦琐配置。

这里先说说项目外层中build.gradle文件的配置,如下:

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.0.1'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}

这些代码都是自动生成的,大部分情况下不需要我们去修改,但也得大概知道其意思。

首先两处repositories的闭包中声明了google()、jcenter()配置,它们代表不同的代码托管仓库,很多的Android开源项目都会或多或少引用了谷歌提供开源项目,所以需要声明google(),而很多的Android开源项目都会选择将代码托管到jcenter上,声明了jcenter之后,我们就可以很方便的使用任何jcenter上的开源项目了。

接下来,dependencies闭包中使用了classpath声明了一个Gradle插件。为什么要声明这个插件呢?原来Gradle并不只是专门为构建Android项目而开发的,java、C++等很多项目都可以使用Gradle来构建。因此想要使用它来构建Android项目,则需要声明com.android.tools.build:gradle:3.0.1'这个插件,其中,最后冒号后面部分是插件的版本号,例如我现在这个项目中使用的插件版本是3.0.1.

分析完外层的build.gradle文件后,还需要分析模块里面的build.gradle文件,如下:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 26
    buildToolsVersion "26.0.2"
    defaultConfig {
        applicationId "com.anand.activitylifecycletest"
        minSdkVersion 15
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:26.0.0-beta1'
    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:0.5'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:2.2.2'
}

这个文件相对复杂一些,首先第一行应用了一个插件,一般有两种值可选:com.android.application表示这是一个应用程序模块,com.android.library表示这是一个库模块。应用程序模块与库模块最大的区别在于一个是可以直接运行的,一个只能作为代码库依附于别的应用程序模块来运行。

紧接着是android这个闭包,可以配置项目构建的各种属性。其中,compileSdkVersion用于指定项目的编译版本,这里指定26表示使用Android 8.0系统的SDK编译,buildToolsVersion用于指定项目构建工具的版本,这里使用了26.0.2版本。

接着是嵌套下的defaultConfig闭包,defaultConfig闭包中可以对项目进行更多的配置。其中,applicationId用于指定项目的包名,一般修改应用包名,可对这个配置进行修改。minSdkVersion用于指定项目最低兼容的Android系统版本,这里指定成15表示最低兼容到Android 4.0系统。targetSdkVersion指定的值表示在该目标版本上已经做过了充分测试,系统将会为其应用程序启用一些最新的功能和特性。举例说Android 6.0系统中引入了运行时权限这个功能,如果我们将targetSdkVersion指定成23或者更高,那么系统就会认为你的程序已经做好充分测试,将为你启用运行时权限,而如果将targetSdkVersion指定成22,那么说明程序最高只在Android 5.1系统上做过充分的测试,Android 6.0系统中引入的新功能自然就不会启用。剩下的versionCode用于指定项目的版本号,versionName用于指定项目版本名,这个两个在安装应用文件以及版本升级方面比较重要。testInstrumentationRunner为谷歌推荐的
AndroidJUnitRunner单元测试(这块是Android Studio2.2以后推出的,这块我也是第一次接触,后期有学习再深入探索)

接着分析下buildTypes闭包。buildTypes闭包用于指定生成安装文件的相关配置。通常情况下会有两个子闭包,一个debug,一个releasedebug闭包用于指定生成测试版安装文件的配置,release闭包用于指定生成正式版安装文件的配置。另外,debug闭包是可以忽略不写的,因此默认情况下我们看到代码中只有一个release闭包。接下来,我们来看下debugrelease闭包中具体内容吧,minifyEnable用于指定是否对项目代码进行混淆操作,true表示混淆,false 表示不混淆。proguardFiles用于指定混淆时使用的规则文件,这里指定了两个文件,第一个proguard-android.txt是在Android SDK下\tools\proguard目录下,这里是所有项目的通用的混淆规则;第二个proguard-rules.pro是在当前项目的根目录下的,里面可以编写当前项目特有的混淆规则。需要注意的是,通过AS直接运行项目生成都是测试版本安装文件,除非手动切换BuildVariants设置。

分析完android闭包,紧接着分析最后一个dependencies闭包。这个闭包主要作用在于指定当前项目所有的依赖关系。通常AS项目一共有3种依赖关系:本地依赖库依赖远程依赖本地依赖可以对本地的Jar包、aar包或者目录添加依赖关系,库依赖可以对项目中的库模块添加依赖关系,远程依赖则可以对jcenter库上的开源项目添加依赖关系。
观察dependencies闭包中的配置,第一行implementation fileTree就是一个本地依赖声明,表示将 libs目录下所有.jar后缀的文件都添加到项目的构建路径当中。而第二行的implementation则是远程依赖声明,com.android.support:appcompat-v7:26.0.0-beta1就是一个标准的远程依赖库格式,其中com.android.support是域名部分,用于和其他公司的库做区分;appcompat-v7是组名称,用于和同一个公司中不同的库做区分;26.0.0-beta1是版本号,用于和同一个库不同的版本做区分。加上这句声明后,Gradle在构建项目时会首先检查一下本地是否已经存在这个库的缓存,如果没有的话则会自动去互联网下载,然后再添加到项目的构建路径当中。至于库依赖这里没有使用到,它的基本格式是implementation project后面加上要依赖的库名称,例如有一个库模块的名称叫helper,那么添加这个库依赖的声明只需要加入implementation project(':helper')即可。后面一些是声明主要是为了声明测试用例库的,后期会单独详细说明下,具体参考Android 项目中的几种单元测试用例。

Android 的日志工具使用

Android中使用的日志工具是Log(android.util.Log),这个类提供了5个方法来打印日志。

  • Log.v()。用于打印那些最为琐碎的、意义最小的日志信息。对应级别verbose,是Android日志里面级别最低的一种。
  • Log.d()。用于打印一些调式信息,这些信息对你调试程序和分析问题有帮助的。对应级别debug,比verbose高一级。
  • Log.i()。用于打印一些比较重要的数据。这些数据应该是开发者非常想要看到的,可以帮助开发者分析用户行为数据。对应级别info,比debug高一级。
  • Log.w()。用于打印一些警告信息,提示程序在这个地方可能会有潜在的风险,最好去修复一下这些出现警告的地方。对应级别warn,比info高一级。
  • Log.e()。用于打印程序中的错误信息,比如程序进入到了catch语句当中。当有错误信息打印出来的时候,一般都代表你的程序出现严重问题了,必须尽快修复。对应级别error,比warn高一级。

关于为什么使用Log而不使用System.out疑问?
System.out.print对应Java初学者开说应该很熟悉,在Eclipse中syso就可以快速打印出信息来,那么为什么Android不使用这个方法,而采用多级别的Log呢,主要的原因是打印不可控、打印时间无法确定、不能添加过滤器、日志没级别区分。对于程序比较复杂的情况下,日志比较多的情况下,快速定位问题无法很快定位到。

关于Log日志一些快捷键操作可以参考《Android Studioc常用快捷键汇总》中的Tab组合快捷键。

除了快捷键, AS还为Log日志提供了locat方便我们过滤查询日志,让我们可以快速定位到对应的日志上。AS目前为开发者提供了3个过滤器,Show only selected application表示只显示当前选中程序中的日志,Firebase是谷歌提供的一个分析工具,No Filters相当于没有过滤器,会把所有的日志都显示出来。当然除了一首AS提供的三种过滤器,也可以自定义自己的过滤器,选择Edit Filter Configuration会弹出一个过滤器配置界面,可以自行配置自定义过滤器,在Log Tag中对需要过滤的tag进行配置。

你可能感兴趣的:(Android 系统概要 ——《第一行代码 Android》)