第 1 章 开始启程——你的第一行Android代码

第 1 章 开始启程——你的第一行Android代码

欢迎你来到Android世界!Android系统是目前世界上市场占有率最高的移动操作系统,不管你在哪里,都可以看到Android手机几乎无处不在。今天的Android世界可谓欣欣向荣,可是你知道它的过去是什么样的吗?我们一起来看一看它的发展史吧。

2003年10月,Andy Rubin等人一起创办了Android公司。2005年8月谷歌收购了这家仅仅成立了22个月的公司,并让Andy Rubin继续负责Android项目。在经过了数年的研发之后,谷歌终于在2008年推出了Android系统的第一个版本。但自那之后,Android的发展就一直受到重重阻挠。乔布斯自始至终认为Android是一个抄袭iPhone的产品,里面剽窃了诸多iPhone的创意,并声称一定要毁掉Android。而本身就是基于Linux开发的Android操作系统,在2010年被Linux团队从Linux内核主线中除名。又由于Android中的应用程序都是使用Java开发的,甲骨文则针对Android侵犯Java知识产权一事对谷歌提起了诉讼……

可是,似乎再多的困难也阻挡不了Android快速前进的步伐。由于谷歌的开放政策,任何手机厂商和个人都能免费获取到Android操作系统的源码,并且可以自由地使用和定制。三星、HTC、摩托罗拉、索爱等公司都推出了各自系列的Android手机,Android市场上百花齐放。仅仅推出两年后,Android就超过了已经霸占市场逾十年的诺基亚Symbian,成为了全球第一大智能手机操作系统,并且每天都还会有数百万台新的Android设备被激活。而近几年,国内的手机厂商也是大放异彩,小米、华为、魅族等新兴品牌都推出了相当不错的Android手机,并且也获得了市场的广泛认可,目前Android已经占据了全球智能手机操作系统70%以上的份额。

说了这些,想必你已经体会到Android系统炙手可热的程度,并且迫不及待地想要加入到Android开发者的行列当中了吧。试想一下,十个人中有七个人的手机都可以运行你编写的应用程序,还有什么能比这个更诱人的呢?那么从今天起,我就带你踏上学习Android的旅途,一步步地引导你成为一名出色的Android开发者。

好了,现在我们就来一起初窥一下Android世界吧。

1.1 了解全貌——Android王国简介

Android从面世以来到现在已经发布了二十几个版本了。在这几年的发展过程中,谷歌为Android王国建立了一个完整的生态系统。手机厂商、开发者、用户之间相互依存,共同推进着Android的蓬勃发展。开发者在其中扮演着不可或缺的角色,因为如果没有开发者来制作丰富的应用程序,那么不管多么优秀的操作系统,也是难以得到大众用户喜爱的,相信没有多少人能够忍受没有QQ、微信的手机吧。而且,谷歌推出的Google Play更是给开发者带来了大量的机遇,只要你能制作出优秀的产品,在Google Play上获得了用户的认可,你就完全可以得到不错的经济回报,从而成为一名独立开发者,甚至是成功创业!

那我们现在就以一个开发者的角度,去了解一下这个操作系统吧。纯理论型的东西也比较无聊,怕你看睡着了,因此我只挑重点介绍,这些东西跟你以后的开发工作都是息息相关的。

1.1.1 Android系统架构

为了让你能够更好地理解Android系统是怎么工作的,我们先来看一下它的系统架构。Android大致可以分为四层架构:Linux内核层、系统运行库层、应用框架层和应用层。

  1. Linux内核层

    Android系统是基于Linux内核的,这一层为Android设备的各种硬件提供了底层的驱动,如显示驱动、音频驱动、照相机驱动、蓝牙驱动、Wi-Fi驱动、电源管理等。

  2. 系统运行库层

    这一层通过一些C/C++库来为Android系统提供了主要的特性支持。如SQLite库提供了数据库的支持,OpenGL|ES库提供了3D绘图的支持,Webkit库提供了浏览器内核的支持等。

    同样在这一层还有Android运行时库,它主要提供了一些核心库,能够允许开发者使用Java语言来编写Android应用。另外,Android运行时库中还包含了Dalvik虚拟机(5.0系统之后改为ART运行环境),它使得每一个Android应用都能运行在独立的进程当中,并且拥有一个自己的Dalvik虚拟机实例。相较于Java虚拟机,Dalvik是专门为移动设备定制的,它针对手机内存、CPU性能有限等情况做了优化处理。

  3. 应用框架层

    这一层主要提供了构建应用程序时可能用到的各种API,Android自带的一些核心应用就是使用这些API完成的,开发者也可以通过使用这些API来构建自己的应用程序。

  4. 应用层

    所有安装在手机上的应用程序都是属于这一层的,比如系统自带的联系人、短信等程序,或者是你从Google Play上下载的小游戏,当然还包括你自己开发的程序。

    结合图1.1你将会理解得更加深刻,图片源自维基百科。

    {%}

    图 1.1 Android系统架构

1.1.2 Android已发布的版本

2008年9月,谷歌正式发布了Android 1.0系统,这也是Android系统最早的版本。随后的几年,谷歌以惊人的速度不断地更新Android系统,2.1、2.2、2.3系统的推出使Android占据了大量的市场。2011年2月,谷歌发布了Android 3.0系统,这个系统版本是专门为平板电脑设计的,但也是Android为数不多的比较失败的版本,推出之后一直不见什么起色,市场份额也少得可怜。不过很快,在同年的10月,谷歌又发布了Android 4.0系统,这个版本不再对手机和平板进行差异化区分,既可以应用在手机上,也可以应用在平板上。2014年Google I/O大会上,谷歌推出了号称史上版本改动最大的Android 5.0系统,其中使用ART运行环境替代了Dalvik虚拟机,大大提升了应用的运行速度,还提出了Material Design的概念来优化应用的界面设计。除此之外,还推出了Android Wear、Android Auto、Android TV系统,从而进军可穿戴设备、汽车、电视等全新领域。之后Android的更新速度更加迅速,2015年Google I/O大会上推出了Android 6.0系统,加入运行时权限功能,2016年Google I/O大会上推出了Android 7.0系统,加入多窗口模式功能,这也是目前最新的Android系统版本。

下表列出了目前主要的Android系统版本及其详细信息。你看到这张表格时,数据可能已经发生了变化,查看最新的数据可以访问http://developer.android.google.cn/about/dashboards/

版本号

系统代号

API

市场占有率

2.2

Froyo

8

0.1%

2.3.3 – 2.3.7

Gingerbread

10

1.5%

4.0.3 – 4.0.4

Ice Cream Sandwich

15

1.3%

4.1.x
4.2.x
4.3

Jelly Bean

16
17
18

5.6%
7.7%
2.3%

4.4

KitKat

19

27.7%

5.0
5.1

Lollipop

21
22

13.1%
21.9%

6.0

Marshmallow

23

18.7%

7.0

Nougat

24

0.1%

从上表中可以看出,目前4.0以上的系统已经占据了超过98%的Android市场份额,因此我们本书中开发的程序也只面向4.0以上的系统,2.x的系统就不再去兼容了。

1.1.3 Android应用开发特色

预告一下,你马上就要开始真正的Android开发旅程了。不过先别急,在开始之前我们再来一起看一看,Android系统到底提供了哪些东西,可供我们开发出优秀的应用程序。

  1. 四大组件

    Android系统四大组件分别是活动(Activity)、服务(Service)、广播接收器(Broadcast Receiver)和内容提供器(Content Provider)。其中活动是所有Android应用程序的门面,凡是在应用中你看得到的东西,都是放在活动中的。而服务就比较低调了,你无法看到它,但它会一直在后台默默地运行,即使用户退出了应用,服务仍然是可以继续运行的。广播接收器允许你的应用接收来自各处的广播消息,比如电话、短信等,当然你的应用同样也可以向外发出广播消息。内容提供器则为应用程序之间共享数据提供了可能,比如你想要读取系统电话簿中的联系人,就需要通过内容提供器来实现。

  2. 丰富的系统控件

    Android系统为开发者提供了丰富的系统控件,使得我们可以很轻松地编写出漂亮的界面。当然如果你品位比较高,不满足于系统自带的控件效果,也完全可以定制属于自己的控件。

  3. SQLite数据库

    Android系统还自带了这种轻量级、运算速度极快的嵌入式关系型数据库。它不仅支持标准的SQL语法,还可以通过Android封装好的API进行操作,让存储和读取数据变得非常方便。

  4. 强大的多媒体

    Android系统还提供了丰富的多媒体服务,如音乐、视频、录音、拍照、闹铃,等等,这一切你都可以在程序中通过代码进行控制,让你的应用变得更加丰富多彩。

  5. 地理位置定位

    移动设备和PC相比起来,地理位置定位功能应该可以算是很大的一个亮点。现在的Android手机都内置有GPS,走到哪儿都可以定位到自己的位置,发挥你的想象就可以做出创意十足的应用,如果再结合功能强大的地图功能,LBS这一领域潜力无限。

既然有Android这样出色的系统给我们提供了这么丰富的工具,你还用担心做不出优秀的应用吗?好了,纯理论的东西就介绍到这里,我知道你已经迫不及待想要开始真正的开发之旅了,那我们就开始启程吧!

1.2 手把手带你搭建开发环境

俗话说得好,“工欲善其事,必先利其器”,开着记事本就想去开发Android程序显然不是明智之举,选择一个好的IDE可以极大幅度地提高你的开发效率,因此本节我就将手把手带着你把开发环境搭建起来。

1.2.1 准备所需要的工具

我现在对你了解还并不多,但我希望你已经是一个颇有经验的Java程序员,这样你理解本书的内容时将会轻而易举,因为Android程序都是使用Java语言编写的。如果你对Java只是略有了解,那阅读本书应该会有一点困难,不过一边阅读一边补充Java知识也是可以的。但如果你对Java完全没有了解,那么我建议你可以暂时将本书放下,先买本介绍Java基础知识的书学上两个星期,把Java的基本语法和特性都学会了,再来继续阅读这本书。

好了,既然你已经阅读到这里,说明你已经掌握Java的基本用法了,下面我们就来看一看开发Android程序需要准备哪些工具。

  • JDK。JDK是Java语言的软件开发工具包,它包含了Java的运行环境、工具集合、基础类库等内容。需要注意的是,本书中的Android程序必须要使用JDK 8或以上版本才能进行开发。

  • Android SDK。Android SDK是谷歌提供的Android开发工具包,在开发Android程序时,我们需要通过引入该工具包,来使用Android相关的API。

  • Android Studio。在很早之前,Android项目都是用Eclipse来开发的,相信所有Java开发者都一定会对这个工具非常熟悉,它是Java开发神器,安装ADT插件后就可以用来开发Android程序了。而在2013年的时候,谷歌推出了一款官方的IDE工具Android Studio,由于不再是以插件的形式存在,Android Studio在开发Android程序方面要远比Eclipse强大和方便得多。不过由于Android Studio早期的测试版本并不是非常稳定,所以本书的第1版仍然选用Eclipse来作为开发工具。而如今,Android Studio已经推出了2.2版本,稳定性完全不再是问题,普及程度方面也远超Eclipse,没有比现在更适合的时机来换用Android Studio了,因此本书中所有的代码都将在Android Studio上进行开发。

1.2.2 搭建开发环境

当然,上述软件并不需要你去一个个地下载,因为谷歌为了简化搭建开发环境的过程,将所有需要用到的工具都帮我们集成好了,到Android官网就可以下载最新的开发工具,下载地址是:https://developer.android.google.cn/studio/index.html。不过,Android官网通常都需要科学上网才能访问,如果你无法访问的话,也可以直接到我的百度网盘去下载,下载地址是:https://pan.baidu.com/s/1nuABMDb。(注意网址中是阿拉伯数字1,而不是英文字母l,网址区分字母大小写。)

你下载下来的将是一个安装包,安装的过程也很简单,一直点击Next就可以了。其中选择安装组件时建议全部勾上,如图1.2所示。

{%}

图 1.2 选择安装组件

接下来还会让你选择Android Studio的安装地址以及Android SDK的安装地址,这些根据你自己电脑的实际情况选择就行了,不想改动的话就保持默认,如图1.3所示。

{%}

图 1.3 选择安装地址

后面就没什么需要注意的了,全部保持默认项,一直点击Next即可完成安装,如图1.4所示。

{%}

图 1.4 安装完成

现在点击Finish按钮来启动Android Studio,一开始会让你选择是否导入之前Android Studio版本的配置,由于这是我们首次安装,这里选择不导入就可以了,如图1.5所示。

{%}

图 1.5 选择不导入配置

点击OK按钮会进入到Android Studio的配置界面,如图1.6所示。

{%}

图 1.6 Android Studio的配置界面

然后点击Next开始进行具体的配置,如图1.7所示。

{%}

图 1.7 选择安装类型

这里我们可以选择Android Studio的安装类型,有Standard和Custom两种。Standard表示一切都使用默认的配置,比较方便;Custom则可以根据用户的特殊需求进行自定义。简单起见,这里我们就选择Standard类型了,继续点击Next完成配置工作,如图1.8所示。

{%}

图 1.8 完成Android Studio配置

现在点击Finish按钮,配置工作就全部完成了。然后Android Studio会尝试联网下载一些更新,等待更新完成后再点击Finish按钮就会进入Android Studio的欢迎界面,如图1.9所示。

{%}

图 1.9 Android Studio的欢迎界面

目前为止,Android开发环境就已经全部搭建完成了。那现在应该做什么?当然是写下你的第一行Android代码了,让我们快点开始吧。

1.3 创建你的第一个Android项目

任何一个编程语言写出的第一个程序毫无疑问都会是Hello World,这已经是自20世纪70年代一直流传下来的传统,在编程界已成为永恒的经典,那我们当然也不会搞例外了。

1.3.1 创建HelloWorld项目

在Android Studio的欢迎界面点击Start a new Android Studio project,会打开一个创建新项目的界面,如图1.10所示。

{%}

图 1.10 创建新项目

其中Application name表示应用名称,此应用安装到手机之后会在手机上显示该名称,这里我们填入HelloWorld。Company Domain表示公司域名,如果是个人开发者,没有公司域名的话,那么就像我一样填example.com就可以了。Package name表示项目的包名,Android系统就是通过包名来区分不同应用程序的,因此包名一定要具有唯一性。Android Studio会根据应用名称和公司域名来自动帮我们生成合适的包名,如果你不想使用默认生成的包名,也可以点击右侧的Edit按钮自行修改。最后,Project location表示项目代码存放的位置,如果没有特殊要求的话,这里也保持默认就可以了。

接下来点击Next可以对项目的最低兼容版本进行设置,如图1.11所示。

{%}

图 1.11 设置项目的最低兼容版本

前面已经说过,Android 4.0以上的系统已经占据了超过98%的Android市场份额,因此这里我们将Minimum SDK指定成API 15就可以了。另外,Wear、TV和Android Auto这几个选项分别是用于开发可穿戴设备、电视和汽车程序的,目前这几个领域在国内还没有普及,我们暂时就先忽略吧。接着点击Next会跳转到创建活动界面,这里我们可以选择一种模板,如图1.12所示。

{%}

图 1.12 选择模板

可以看到,Android Studio提供了很多种内置模板,不过由于我们才刚刚开始学习,用不着这么多复杂的模板,这里直接选择Empty Activity来创建一个空的活动就可以了。

继续点击Next,可以给创建的活动和布局命名,如图1.13所示。

{%}

图 1.13 给活动和布局命名

其中,Activity Name表示活动的名字,这里填入HelloWorldActivity,Layout Name表示布局的命名,这里填入hello_world_layout。然后点击Finish按钮,并耐心等待一会儿,项目就会创建成功了,如图1.14所示。

{%}

图 1.14 项目创建成功

1.3.2 启动模拟器

由于Android Studio自动为我们生成了很多东西,你现在不需要编写任何代码,HelloWorld项目就已经可以运行了。但是在此之前还必须要有一个运行的载体,可以是一部Android手机,也可以是Android模拟器。这里我们暂时先使用模拟器来运行程序,如果你想立刻就将程序运行到手机上的话,可以参考8.1节的内容。

那么我们现在就来创建一个Android模拟器,观察Android Studio顶部工具栏中的图标,如图1.15所示。

{%}

图 1.15 顶部工具栏中的图标

其中,最左边的按钮就是用于创建和启动模拟器的,点击该按钮,会弹出如图1.16所示的窗口。

{%}

图 1.16 创建模拟器

可以看到,目前我们的模拟器列表中还是空的,点击Create Virtual Device按钮就可以立刻开始创建了,如图1.17所示。

{%}

图 1.17 选择要创建的模拟器设备

这里有很多种设备可供我们选择,不仅能创建手机模拟器,还可以创建平板、手表、电视等模拟器。

那么我就选择创建Nexus 5X这台设备的模拟器了,点击Next,如图1.18所示。

{%}

图 1.18 选择模拟器的操作系统版本

这里可以选择模拟器所使用的操作系统版本,毫无疑问,我们肯定要选择最新的Android 7.0系统。继续点击Next,如图1.19所示。

{%}

图 1.19 确认模拟器配置

在这里我们可以对模拟器的一些配置进行确认,比如说指定模拟器的名字、分辨率、横竖屏等信息,如果没有特殊需求的话,全部保持默认就可以了。点击Finish完成模拟器的创建,然后会弹出如图1.20所示的窗口。

{%}

图 1.20 模拟器列表

可以看到,现在模拟器列表中已经存在一个创建好的模拟器设备了,点击Actions栏目中最左边的三角形按钮即可启动模拟器。模拟器会像手机一样,有一个开机过程,启动完成之后的界面如图1.21所示。

{%}

图 1.21 启动后的模拟器界面

很清新的Android界面出来了!看上去还挺不错吧,你几乎可以像使用手机一样使用它,Android模拟器对手机的模仿度非常高,快去体验一下吧。

1.3.3 运行HelloWorld

现在模拟器已经启动起来了,那么下面我们就开始将HelloWorld项目运行到模拟器上。观察Android Studio顶部工具栏中的图标,如图1.22所示。其中左边的锤子按钮是用来编译项目的,中间的下拉列表是用来选择运行哪一个项目的,通常app就是当前的主项目,右边的三角形按钮是用来运行项目的。

{%}

图 1.22 顶部工具栏中的图标

现在点击右边的运行按钮,会弹出一个选择运行设备的对话框,如图1.23所示。

{%}

图 1.23 选择运行设备对话框

可以看到,我们刚刚创建的模拟器现在是在线的,点击OK按钮,稍微等待一会儿,HelloWorld项目就会运行到模拟器上了,结果应该和图1.24中显示的是一样的。

{%}

图 1.24 运行HelloWorld项目

HelloWorld项目运行成功!并且你会发现,模拟器上已经安装上HelloWorld这个应用了。打开启动器列表,如图1.25所示。

{%}

图 1.25 查看启动器列表

这个时候你可能会说我坑你了,说好的第一行代码呢?怎么一行还没写,项目就已经运行起来了?这个只能说是因为Android Studio太智能了,已经帮我们把一些简单内容都自动生成了。你也别心急,后面写代码的机会多着呢,我们先来分析一下HelloWorld这个项目吧。

1.3.4 分析你的第一个Android程序

回到Android Studio当中,首先展开HelloWorld项目,你会看到如图1.26所示的项目结构。

{%}

图 1.26 Android模式的项目结构

任何一个新建的项目都会默认使用Android模式的项目结构,但这并不是项目真实的目录结构,而是被Android Studio转换过的。这种项目结构简洁明了,适合进行快速开发,但是对于新手来说可能并不易于理解。点击图1.26当中的Android区域可以切换项目结构模式,如图1.27所示。

{%}

图 1.27 切换项目结构模式

这里我们将项目结构模式切换成Project,这就是项目真实的目录结构了,如图1.28所示。

{%}

图 1.28 Project模式的项目结构

一开始看到这么多陌生的东西,你一定会感到有点头晕吧。别担心,我现在就对图1.28中的内容进行一一讲解,之后你再看这张图就不会感到那么吃力了。

  1. .gradle和.idea

    这两个目录下放置的都是Android Studio自动生成的一些文件,我们无须关心,也不要去手动编辑。

  2. app

    项目中的代码、资源等内容几乎都是放置在这个目录下的,我们后面的开发工作也基本都是在这个目录下进行的,待会儿还会对这个目录单独展开进行讲解。

  3. build

    这个目录你也不需要过多关心,它主要包含了一些在编译时自动生成的文件。

  4. gradle

    这个目录下包含了gradle wrapper的配置文件,使用gradle wrapper的方式不需要提前将gradle下载好,而是会自动根据本地的缓存情况决定是否需要联网下载gradle。Android Studio默认没有启用gradle wrapper的方式,如果需要打开,可以点击Android Studio导航栏→File→Settings→Build, Execution, Deployment→Gradle,进行配置更改。

  5. .gitignore

    这个文件是用来将指定的目录或文件排除在版本控制之外的,关于版本控制我们将在第5章中开始正式的学习。

  6. build.gradle

    这是项目全局的gradle构建脚本,通常这个文件中的内容是不需要修改的。稍后我们将会详细分析gradle构建脚本中的具体内容。

  7. gradle.properties

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

  8. gradlew和gradlew.bat

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

  9. HelloWorld.iml

    iml文件是所有IntelliJ IDEA项目都会自动生成的一个文件(Android Studio是基于IntelliJ IDEA开发的),用于标识这是一个IntelliJ IDEA项目,我们不需要修改这个文件中的任何内容。

  10. local.properties

    这个文件用于指定本机中的Android SDK路径,通常内容都是自动生成的,我们并不需要修改。除非你本机中的Android SDK位置发生了变化,那么就将这个文件中的路径改成新的位置即可。

  11. settings.gradle

    这个文件用于指定项目中所有引入的模块。由于HelloWorld项目中就只有一个app模块,因此该文件中也就只引入了app这一个模块。通常情况下模块的引入都是自动完成的,需要我们手动去修改这个文件的场景可能比较少。

现在整个项目的外层目录结构已经介绍完了。你会发现,除了app目录之外,大多数的文件和目录都是自动生成的,我们并不需要进行修改。想必你已经猜到了,app目录下的内容才是我们以后的工作重点,展开之后结构如图1.29所示。

{%}

图 1.29 app目录下的结构

那么下面我们就来对app目录下的内容进行更为详细的分析。

  1. build

    这个目录和外层的build目录类似,主要也是包含了一些在编译时自动生成的文件,不过它里面的内容会更多更杂,我们不需要过多关心。

  2. libs

    如果你的项目中使用到了第三方jar包,就需要把这些jar包都放在libs目录下,放在这个目录下的jar包都会被自动添加到构建路径里去。

  3. androidTest

    此处是用来编写Android Test测试用例的,可以对项目进行一些自动化测试。

  4. java

    毫无疑问,java目录是放置我们所有Java代码的地方,展开该目录,你将看到我们刚才创建的HelloWorldActivity文件就在里面。

  5. res

    这个目录下的内容就有点多了。简单点说,就是你在项目中使用到的所有图片、布局、字符串等资源都要存放在这个目录下。当然这个目录下还有很多子目录,图片放在drawable目录下,布局放在layout目录下,字符串放在values目录下,所以你不用担心会把整个res目录弄得乱糟糟的。

  6. AndroidManifest.xml

    这是你整个Android项目的配置文件,你在程序中定义的所有四大组件都需要在这个文件里注册,另外还可以在这个文件中给应用程序添加权限声明。由于这个文件以后会经常用到,我们用到的时候再做详细说明。

  7. test

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

  8. .gitignore

    这个文件用于将app模块内的指定的目录或文件排除在版本控制之外,作用和外层的.gitignore文件类似。

  9. app.iml

    IntelliJ IDEA项目自动生成的文件,我们不需要关心或修改这个文件中的内容。

  10. build.gradle

    这是app模块的gradle构建脚本,这个文件中会指定很多项目构建相关的配置,我们稍后将会详细分析gradle构建脚本中的具体内容。

  11. proguard-rules.pro

    这个文件用于指定项目代码的混淆规则,当代码开发完成后打成安装包文件,如果不希望代码被别人破解,通常会将代码进行混淆,从而让破解者难以阅读。

这样整个项目的目录结构就都介绍完了,如果你还不能完全理解的话也很正常,毕竟里面有太多的东西你都还没接触过。不过不用担心,这并不会影响到你后面的学习。等你学完整本书再回来看这个目录结构图时,你会觉得特别地清晰和简单。

接下来我们一起分析一下HelloWorld项目究竟是怎么运行起来的吧。首先打开AndroidManifest.xml文件,从中可以找到如下代码:

<activity android:name=".HelloWorldActivity">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

这段代码表示对HelloWorldActivity这个活动进行注册,没有在AndroidManifest.xml里注册的活动是不能使用的。其中intent-filter里的两行代码非常重要,<action android:name= "android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" />表示HelloWorldActivity是这个项目的主活动,在手机上点击应用图标,首先启动的就是这个活动。

那HelloWorldActivity具体又有什么作用呢?我在介绍Android四大组件的时候说过,活动是Android应用程序的门面,凡是在应用中你看得到的东西,都是放在活动中的。因此你在图1.24中看到的界面,其实就是HelloWorldActivity这个活动。那我们快去看一下它的代码吧,打开HelloWorldActivity,代码如下所示:

public class HelloWorldActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.hello_world_layout);
    }

}

首先我们可以看到,HelloWorldActivity是继承自AppCompatActivity的,这是一种向下兼容的Activity,可以将Activity在各个系统版本中增加的特性和功能最低兼容到Android 2.1系统。Activity是Android系统提供的一个活动基类,我们项目中所有的活动都必须继承它或者它的子类才能拥有活动的特性(AppCompatActivity是Activity的子类)。然后可以看到HelloWorldActivity中有一个onCreate()方法,这个方法是一个活动被创建时必定要执行的方法,其中只有两行代码,并且没有Hello World!的字样。那么图1.24中显示的Hello World!是在哪里定义的呢?

其实Android程序的设计讲究逻辑和视图分离,因此是不推荐在活动中直接编写界面的,更加通用的一种做法是,在布局文件中编写界面,然后在活动中引入进来。可以看到,在onCreate()方法的第二行调用了setContentView()方法,就是这个方法给当前的活动引入了一个hello_world_layout布局,那Hello World!一定就是在这里定义的了!我们快打开这个文件看一看。

布局文件都是定义在res/layout目录下的,当你展开layout目录,你会看到hello_world_layout.xml这个文件。打开该文件并切换到Text视图,代码如下所示:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/hello_world_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.helloworld.HelloWorldActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />
</RelativeLayout>

现在还看不懂?没关系,后面我会对布局进行详细讲解的,你现在只需要看到上面代码中有一个TextView,这是Android系统提供的一个控件,用于在布局中显示文字的。然后你终于在TextView中看到了Hello World!的字样!哈哈!终于找到了,原来就是通过android:text="Hello World!"这句代码定义的。

这样我们就将HelloWorld项目的目录结构以及基本的执行过程都分析完了,相信你对Android项目已经有了一个初步的认识,下一小节中我们就来学习一下项目中所包含的资源。

1.3.5 详解项目中的资源

如果你展开res目录看一下,其实里面的东西还是挺多的,很容易让人看得眼花缭乱,如图1.30所示。

{%}

图 1.30 res目录下的结构

看到这么多的文件夹也不用害怕,其实归纳一下,res目录就变得非常简单了。所有以drawable开头的文件夹都是用来放图片的,所有以mipmap开头的文件夹都是用来放应用图标的,所有以values开头的文件夹都是用来放字符串、样式、颜色等配置的,layout文件夹是用来放布局文件的。怎么样,是不是突然感觉清晰了很多?

之所以有这么多mipmap开头的文件夹,其实主要是为了让程序能够更好地兼容各种设备。drawable文件夹也是相同的道理,虽然Android Studio没有帮我们自动生成,但是我们应该自己创建drawable-hdpi、drawable-xhdpi、drawable-xxhdpi等文件夹。在制作程序的时候最好能够给同一张图片提供几个不同分辨率的版本,分别放在这些文件夹下,然后当程序运行的时候,会自动根据当前运行设备分辨率的高低选择加载哪个文件夹下的图片。当然这只是理想情况,更多的时候美工只会提供给我们一份图片,这时你就把所有图片都放在drawable-xxhdpi文件夹下就好了。

知道了res目录下每个文件夹的含义,我们再来看一下如何去使用这些资源吧。打开res/ values/strings.xml文件,内容如下所示:

<resources>
    <string name="app_name">HelloWorld</string>
</resources>

可以看到,这里定义了一个应用程序名的字符串,我们有以下两种方式来引用它。

  • 在代码中通过R.string.app_name可以获得该字符串的引用。

  • 在XML中通过@string/app_name可以获得该字符串的引用。

基本的语法就是上面这两种方式,其中string部分是可以替换的,如果是引用的图片资源就可以替换成drawable,如果是引用的应用图标就可以替换成mipmap,如果是引用的布局文件就可以替换成layout,以此类推。

下面举一个简单的例子来帮助你理解,打开AndroidManifest.xml文件,找到如下代码:

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    ...
</application>

其中,HelloWorld项目的应用图标就是通过android:icon属性来指定的,应用的名称则是通过android:label属性指定的。可以看到,这里对资源引用的方式正是我们刚刚学过的在XML中引用资源的语法。

经过本小节的学习,如果你想修改应用的图标或者名称,相信已经知道该怎么办了吧。

1.3.6 详解build.gradle文件

不同于Eclipse,Android Studio是采用Gradle来构建项目的。Gradle是一个非常先进的项目构建工具,它使用了一种基于Groovy的领域特定语言(DSL)来声明项目设置,摒弃了传统基于XML(如Ant和Maven)的各种烦琐配置。

在1.3.4小节中我们已经看到,HelloWorld项目中有两个build.gradle文件,一个是在最外层目录下的,一个是在app目录下的。这两个文件对构建Android Studio项目都起到了至关重要的作用,下面我们就来对这两个文件中的内容进行详细的分析。

先来看一下最外层目录下的build.gradle文件,代码如下所示:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.2.0'
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

这些代码都是自动生成的,虽然语法结构看上去可能有点难以理解,但是如果我们忽略语法结构,只看最关键的部分,其实还是很好懂的。

首先,两处repositories的闭包中都声明了jcenter()这行配置,那么这个jcenter是什么意思呢?其实它是一个代码托管仓库,很多Android开源项目都会选择将代码托管到jcenter上,声明了这行配置之后,我们就可以在项目中轻松引用任何jcenter上的开源项目了。

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

这样我们就将最外层目录下的build.gradle文件分析完了,通常情况下你并不需要修改这个文件中的内容,除非你想添加一些全局的项目构建配置。

下面我们再来看一下app目录下的build.gradle文件,代码如下所示:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 24
    buildToolsVersion "24.0.2"
    defaultConfig {
        applicationId "com.example.helloworld"
        minSdkVersion 15
        targetSdkVersion 24
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'),
                'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:24.2.1'
    testCompile 'junit:junit:4.12'
}

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

接下来是一个大的android闭包,在这个闭包中我们可以配置项目构建的各种属性。其中,compileSdkVersion用于指定项目的编译版本,这里指定成24表示使用Android 7.0系统的SDK编译。buildToolsVersion用于指定项目构建工具的版本,目前最新的版本就是24.0.2,如果有更新的版本时,Android Studio会进行提示。

然后我们看到,这里在android闭包中又嵌套了一个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用于指定项目的版本名,这两个属性在生成安装文件的时候非常重要,我们在后面都会学到。

分析完了defaultConfig闭包,接下来我们看一下buildTypes闭包。buildTypes闭包中用于指定生成安装文件的相关配置,通常只会有两个子闭包,一个是debug,一个是release。debug闭包用于指定生成测试版安装文件的配置,release闭包用于指定生成正式版安装文件的配置。另外,debug闭包是可以忽略不写的,因此我们看到上面的代码中就只有一个release闭包。下面来看一下release闭包中的具体内容吧,minifyEnabled用于指定是否对项目的代码进行混淆,true表示混淆,false表示不混淆。proguardFiles用于指定混淆时使用的规则文件,这里指定了两个文件,第一个proguard-android.txt是在Android SDK目录下的,里面是所有项目通用的混淆规则,第二个proguard-rules.pro是在当前项目的根目录下的,里面可以编写当前项目特有的混淆规则。需要注意的是,通过Android Studio直接运行项目生成的都是测试版安装文件,关于如何生成正式版安装文件我们将会在第15章中学习。

这样整个android闭包中的内容就都分析完了,接下来还剩一个dependencies闭包。这个闭包的功能非常强大,它可以指定当前项目所有的依赖关系。通常Android Studio项目一共有3种依赖方式:本地依赖、库依赖和远程依赖。本地依赖可以对本地的Jar包或目录添加依赖关系,库依赖可以对项目中的库模块添加依赖关系,远程依赖则可以对jcenter库上的开源项目添加依赖关系。观察一下dependencies闭包中的配置,第一行的compile fileTree就是一个本地依赖声明,它表示将libs目录下所有.jar后缀的文件都添加到项目的构建路径当中。而第二行的compile则是远程依赖声明,com.android.support:appcompat-v7:24.2.1就是一个标准的远程依赖库格式,其中com.android.support是域名部分,用于和其他公司的库做区分;appcompat-v7是组名称,用于和同一个公司中不同的库做区分;24.2.1是版本号,用于和同一个库不同的版本做区分。加上这句声明后,Gradle在构建项目时会首先检查一下本地是否已经有这个库的缓存,如果没有的话则会去自动联网下载,然后再添加到项目的构建路径当中。至于库依赖声明这里没有用到,它的基本格式是compile project后面加上要依赖的库名称,比如说有一个库模块的名字叫helper,那么添加这个库的依赖关系只需要加入compile project(':helper')这句声明即可。另外剩下的一句testCompile是用于声明测试用例库的,这个我们暂时用不到,先忽略它就可以了。

1.4 前行必备——掌握日志工具的使用

通过上一节的学习,你已经成功创建了你的第一个Android程序,并且对Android项目的目录结构和运行流程都有了一定的了解。现在本应该是你继续前行的时候,不过我想在这里给你穿插一点内容,讲解一下Android中日志工具的使用方法,这对你以后的Android开发之旅会有极大的帮助。

1.4.1 使用Android的日志工具Log

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高一级。

其实很简单,一共就5个方法,当然每个方法还会有不同的重载,但那对你来说肯定不是什么难理解的地方了。我们现在就在HelloWorld项目中试一试日志工具好不好用吧。

打开HelloWorldActivity,在onCreate()方法中添加一行打印日志的语句,如下所示:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.hello_world_layout);
    Log.d("HelloWorldActivity", "onCreate execute");
}

Log.d()方法中传入了两个参数:第一个参数是tag,一般传入当前的类名就好,主要用于对打印信息进行过滤;第二个参数是msg,即想要打印的具体的内容。

现在可以重新运行一下HelloWorld这个项目了,点击顶部工具栏上的运行按钮,或者使用快捷键Shift + F10(Mac系统是control + R),等程序运行完毕,点击Android Studio底部工具栏的Android Monitor,在logcat中就可以看到打印信息了,如图1.31所示。

{%}

图 1.31 logcat中的打印信息

其中,你不仅可以看到打印日志的内容和tag名,就连程序的包名、打印的时间以及应用程序的进程号都可以看到。

另外,不知道你有没有注意到,你的第一行代码已经在不知不觉中写出来了,我也总算是交差了。

1.4.2 为什么使用Log而不使用System.out

我相信很多的Java新手都非常喜欢使用System.out.println()方法来打印日志,不知道你是不是也喜欢这么做。不过在真正的项目开发中,是极度不建议使用System.out.println()方法的!如果你在公司的项目中经常使用这个方法,就很有可能要挨骂了。

为什么System.out.println()方法会这么遭大家唾弃呢?经过我仔细分析之后,发现这个方法除了使用方便一点之外,其他就一无是处了。方便在哪儿呢?在Eclipse中你只需要输入syso,然后按下代码提示键,这个方法就会自动出来了,相信这也是很多Java新手对它钟情的原因。那缺点又在哪儿了呢?这个就太多了,比如日志打印不可控制、打印时间无法确定、不能添加过滤器、日志没有级别区分……

听我说了这些,你可能已经不太想用System.out.println()方法了,那么Log就把上面所说的缺点全部都改好了吗?虽然谈不上全部,但我觉得Log已经做得相当不错了。我现在就来带你看看Log和logcat配合的强大之处。

首先刚才提到的快捷输入,在Android Studio当中也是有的,比如你想打印一条debug级别的日志,那么只需要输入logd,然后按下Tab键,就会帮你自动补全一条完整的打印语句。输入logi,然后按下Tab键,会自动补全一条info级别的打印日志。输入logw,按下Tab键,会自动补全一条warn级别的打印日志,以此类推。另外,由于Log的所有打印方法都要求传入一个tag参数,每次写一遍显然太过麻烦。这里还有一个小技巧,我们在onCreate()方法的外面输入logt,然后按下Tab键,这时就会以当前的类名作为值自动生成一个TAG常量,如下所示:

public class HelloWorldActivity extends AppCompatActivity {

    private static final String TAG = "HelloWorldActivity";

    ...
}

除了快捷输入之外,logcat中还能很轻松地添加过滤器,你可以在图1.32中看到我们目前所有的过滤器。

{%}

图 1.32 logcat中的过滤器

目前只有3个过滤器,Show only selected application表示只显示当前选中程序的日志, Firebase是谷歌提供的一个分析工具,我们可以不用管它,No Filters相当于没有过滤器,会把所有的日志都显示出来。那可不可以自定义过滤器呢?当然可以,我们现在就来添加一个过滤器试试。

点击图1.32中的Edit Filter Configuration,会弹出一个过滤器配置界面。我们给过滤器起名叫data,并且让它对名为data的tag进行过滤,如图1.33所示。

{%}

图 1.33 过滤器配置界面

点击OK,你就会发现你已经多出了一个data过滤器。当你点击这个过滤器的时候,你会发现刚才在onCreate()方法里打印的日志没了,这是因为data这个过滤器只会显示tag名称为data的日志。你可以尝试在onCreate()方法中把打印日志的语句改成Log.d("data", "onCreate execute"),然后再次运行程序,你就会在data过滤器下看到这行日志了。

不知道你有没有体会到使用过滤器的好处,可能现在还没有吧。不过当你的程序打印出成百上千行日志的时候,你就会迫切地需要过滤器了。

看完了过滤器,再来看一下logcat中的日志级别控制吧。logcat中主要有5个级别,分别对应着上一节介绍的5个方法,如图1.34所示。

{%}

图 1.34 logcat中的日志级别

当前我们选中的级别是verbose,也就是最低等级。这意味着不管我们使用哪一个方法打印日志,这条日志都一定会显示出来。而如果我们将级别选中为debug,这时只有我们使用debug及以上级别方法打印的日志才会显示出来,以此类推。你可以做一下试验,当你把logcat中的级别选中为info、warn或者error时,我们在onCreate()方法中打印的语句是不会显示的,因为我们打印日志时使用的是Log.d()方法。

日志级别控制的好处就是,你可以很快地找到你所关心的那些日志。相信如果让你从上千行日志中查找一条崩溃信息,你一定会抓狂的吧。而现在你只需要将日志级别选中为error,那些不相干的琐碎信息就不会再干扰你的视线了。

最后我们再来看一下关键字过滤。如果使用过滤器加日志级别控制还是不能锁定到你想查看的日志内容的话,那么还可以通过关键字进行进一步的过滤,如图1.35所示。

{%}

图 1.35 关键字输入框

我们可以在输入框里输入关键字的内容,这样只有符合关键字条件的日志才会显示出来,从而能够快速定位到任何你想查看的日志。另外还有一点需要注意,关键字过滤是支持正则表达式的,有了这个特性,我们就可以构建出更加丰富的过滤条件。

关于Android中日志工具的使用我就准备讲到这里,logcat中其他的一些使用技巧就要靠你自己去摸索了。今天你已经学到了足够多的东西,我们来总结和梳理一下吧。

1.5 小结与点评

你现在一定会觉得很充实,甚至有点沾沾自喜。确实应该如此,因为你已经成为一名真正的Android开发者了。通过本章的学习,你首先对Android系统有了更加充足的认识,然后成功将Android开发环境搭建了起来,接着创建了你自己的第一个Android项目,并对Android项目的目录结构和执行过程有了一定的认识,在本章的最后还学习了Android日志工具的使用,这难道还不够充实吗?

不过你也别太过于满足,相信你很清楚,Android开发者和出色的Android开发者还是有很大的区别的,你还需要付出更多的努力才行。即使你目前在Java领域已经有了不错的成绩,我也希望在Android的世界你可以放下身段,以一只萌级小菜鸟的身份起飞,在后面的旅途中你会不断地成长。

现在你可以非常安心地休息一段时间,因为今天你已经做得非常不错了。储备好能量,准备进入到下一章的旅程当中。

目录

  • 前言
  • 致谢
  • 第 1 章 开始启程——你的第一行Android代码
  • 第 2 章 先从看得到的入手——探究活动
  • 第 3 章 软件也要拼脸蛋——UI开发的点点滴滴
  • 第 4 章 手机平板要兼顾——探究碎片
  • 第 5 章 全局大喇叭——详解广播机制
  • 第 6 章 数据存储全方案——详解持久化技术
  • 第 7 章 跨程序共享数据——探究内容提供器
  • 第 8 章 丰富你的程序——运用手机多媒体
  • 第 9 章 看看精彩的世界——使用网络技术
  • 第 10 章 后台默默的劳动者——探究服务
  • 第 11 章 Android特色开发——基于位置的服务
  • 第 12 章 最佳的UI体验——Material Design实战
  • 第 13 章 继续进阶——你还应该掌握的高级技巧
  • 第 14 章 进入实战——开发酷欧天气
  • 第 15 章 最后一步——将应用发布到360应用商店