Java转身系列之安卓2 : Android Studio的代码工程组织——Gradle、App构建
Java转身系列之安卓 —— Android Studio的代码工程组织方式
从Ant、Maven到Gradle
编程的最终目标是将软件运行起来,编译是连接编程与程序运行的关键环节。
Java编译指令是javac,它将文本源代码编译成.class字节码文件,虚拟机装载字节码文件,进行解析、链接和运行。
javac com.example.Main
软件体积越大,如何组织代码、管理依赖、编译运行及测试,就需要有成体系的方法和工具进行支持,否则依靠人工进行重复的命令输入编译,会令人不胜其烦,效率低下。
C语言程序猿有Makefile,Java在2000年有了Ant,它用java实现了cmake的机制,并且用当时的“网红”XML作为描述文件。Ant比cmake进步了好多,但依然需要在xml中写多个task来完成工作,Ant一开始没有一致的依赖仓库进行统一管理(后来通过子项目Ivy解决),不久后Maven出现。这两个项目都与Jakarta有关。
Maven采用Convention over Configuration(coc),引入项目对象、生命周期、依赖库管理、插件等理念和机制,将代码组织和软件运行部署等提升到新高度,经过多年经营,已成为代码工程组织管理的集大成者,得到业界最普遍支持。
2007年后,Ruby on Rails大热,这个Web框架将Ruby这门与Java一般年龄的语言重新带入大众视野。Ruby简洁、富有表现力的语法,独特的面向对象、天生的元编程以及动态语言等特性,加上ROR在MVC、Active Record数据访问等方面带来了奇高生产效率,令当时传统的Web开发技术如JSP、ASP、PHP等相形见绌,受到硅谷的青睐,成为创业公司首选,这股风潮迅速遍及全世界。
与ROR一起,号称Ruby Make的Rake,也因为Ruby语法在任务执行的“领域”特性吸引了开发者眼球。Rake从相似性讲更接近于Ant,但是它并没有使用xml或者其他结构化文本(如YAML)作为描述和设置文件,而是直接使用了Ruby语言,形成了“代码即配置,配置即代码”的“奇观”。由于Ruby强大的叙述表达能力,Rake在ROR开发、构建、运行、部署这个领域形成了领域特定语言(Domain Specific Language, DSL)。
ROR如一股清流,注入活力渐渐不够的Java社区,后来出现了JRuby与Groovy。Groovy是运行在JVM的动态语言,取法于JavaScript、Ruby、Java、Scala等语言,与Java具有亲缘性,它建立在Java生态环境之上。由于Rake实在是太成功,于是在Groovy之上就有了借鉴Rake思想的Gradle。与Ant、Maven相比,Gradle具有以下一些鲜明特点:
- 无xml配置,使用原生动态语言DSL进行工程管理,任务可灵活定制;
- 支持Maven、Ivy仓库,更多的依赖冲突解决方案;
- 代码工程目录不用遵循类似Maven的固定的目录结构,可定制;
- 支持Java、Kotlin、Scala、Groovy、Webpack、C、C++项目;
- 灵活的多项目管理,尤其适合大型工程组织,使用Gradle的有Android、Spring、Hibernate这类大型项目;
- 对于混合编译的多项目管理,类似用到JNI的Android项目,使用Gradle会更简单。
Android工程目录
这是模板工程的项目视图窗口:
这个视图呈现的并不是工程实际目录结构,而是一个切面(Facet,跟Eclipse的类似)。
一级 | 二级 | 三级 | 文件 | 说明 |
---|---|---|---|---|
App | manifests | AndroidManifest.xml | App入口声明文件 | |
java | 源代码目录 | |||
res | 资源目录 | |||
drawable | 矢量图xml文件,了解svg就不陌生 | |||
layout | 布局xml文件 | |||
menu | 菜单 | |||
mipmap | app启动图标目录 | |||
values | colors.xml strings.xml dimens.xml styles.xml | 值引用,以样式、字符串、颜色、空间位置等分类 | ||
Gradle Scripts | gradle脚本 |
实际的工程目录结构如下:
App代码构成和关系
Android App是手持设备上的“桌面”开发,这是从“外形”上进行简单类比。
经历过传统桌面开发时代的老程序猿知道,桌面开发就是所见所得,通过IDE的支持,拖拽UI组件进行界面设计和开发。那个时代最好的界面开发IDE有Delphi、VB、PB(Power Builder)。以Delphi为例,有专门的Form文件对界面进行描述,IDE有专用的界面设计器与开发者进行设计交互。
Web经过1.0、2.0时代的演进,各种开发理念和开发技术已经深入影响到桌面开发,如内容与样式分离、XML描述、Rich Internet App等,微软WPF XAML、Qt QML、JavaFx FXML是web与桌面融合的典范。
Android界面由一个个Activity组成,通过Activity切换与用户进行交互,Activity也是通过XML进行界面描述。
Activities就像一副扑克牌,用户通过点触一张一张地交互。以下一张图显示了主入口Activity的代码关系:
XML是界面DSL,Activity在onCreate这个钩子方法被调用时,通过R.layout.activity_main这个layout资源id进行界面加载和绘制,R类由IDE自动生成:
Gradle脚本
这是一个Gradle管理的项目:
gradle-wrapper.jar,起到bootstrap的作用,例如自动下载安装gradle;
gradle-wrapper.properties,wrapper的属性配置,例如gradle安装包的下载url地址;
build.gradle,当前项目的配置任务脚本;
gradlew,nix环境shell执行脚本;
gradlew.bat,windows批处理执行文件;
settings.gradle,配置脚本,配置哪些项目包含在本工程中。
Gradle是什么?运行一下这个东西看看。安装好Gradle后(安装方法如同Maven,解压,设置bin路径变量),然后进入一个目录,运行gradle init就可以初始化一个项目:
build.gradle就是一个gradle文件,里边有一个任务hello,输出“hello, gradle”字样,执行gradle hello运行一次:
这个执行发生了以下几件事:
gradle批处理命令通过jvm启动groovy环境,加载gradle;
gradle找到build.gradle文件;
根据批处理入参hello,找到hello任务;
执行hello任务,打印出”hello, gradle”
这里build.gradle其实就是groovy脚本,task hello {}这个语法就是前面一直提到的DSL, {}之内的内容是闭包——这就是gradle的魔法真相!
关于gradle和groovy的关系,groovy的魔法,由于不是本文重点,在此略过。
Android Gradle脚本
以Android、Project视图查看Android工程,
Android工程是以Gradle多项目形式进行组织,有一个*的build.gradle文件(Project: MyApplication),以及一个app子目录,app拥有自己的build.gradle文件。
settings.gradle用来配置多项目构建,这里指明app子目录是一个gradle模块项目:
include ':app'
以下是*Gradle build文件,
下载插件定义块,告诉gradle从google和jcenter两个源下载android的gradle插件;
android的gradle插件;
*以及模块项目的配置,这里定义了依赖库位置;
当前工程的特定(ad hoc)任务,这里是做build目录的清空操作。
除了*gradle文件负责总体配置外,app下的build.gadle设置了app这个具体子项目的管理信息:
第一行指明使用android插件。
compileSdkVersion指定Android SDK编译版本,通常是最新版本;
defaultConfig栏包含是app的各项属性;
applicationId是app名,在Google Play商店中必须唯一;
minSdkVersion,app要支持的最小api版本;
targetSdkVersion,应与compileSdkVersion一致;
versionCode,整数版本号,在Google Play商店中与applicationId一起起到描述标识作用;
versionName,版本名称,主要是内部版本管理用;
testInstrumentationRunner,配置Junit4作为app的测试运行工具。
dependencies块定义了工程依赖库管理。
配置式引入依赖
Guava对jdk很多地方进行“补强”,现在在工程中引入guava依赖:
编辑根下的build.gradle文件,加入mavenCentral仓库。前面提到,gradle自身也支持maven依赖库管理。
在app下的build.gradle中,引入guava包:
在引入新的依赖后,AS自动会在主编辑区上方提示需要同步gradle设置,点击后自动会下载依赖并构建整个项目:
界面式引入依赖
不喜欢原始的配置式引入依赖,可以通过界面交互来引入依赖。在工程导航Android视图中选择app,右键打开上下文菜单,选择open module settings(打开模块设置),可以通过网络和本地导入依赖:
小结
- Android工程通过Gradle进行项目代码组织和管理,目录呈现父子关系,包含了源代码目录、资源目录、测试目录、gradle脚本;
- Android App以Activity界面方式与用户交互,Activity采用代码与用户界面描述xml分开设计和加载模式;
- 开发者与可以通过AS界面完成与Gradle的设置和调用,但只有了解Gradle的思想,明白它的作用,熟悉基本的配置,才能籍助IDE更好管理App工程,尤其是遇到编译错误时,知道如何解决问题。