Gradle学习
第一章:Gradle 入门
1. 环境搭建
基础环境为Ubuntu16.04
java 安装
sudo apt install openjdk-8-jdk
gradle安装
在官网下载安装包解压到安装目录,在用户目录下.bashrc
文件中或者/etc/profile
中添加环境变量配置。
GRADLE_HOME=/root/UbuntuHome/gradle-2.14
PATH=${PATH}:${GRADLE_HOME}/bin
export GRADLE_HOME PATH
在shell中输入source ~/.bashrc
使配置生效。gradle -v
查看是否安装成功。
2. Groovy基础
Groovy是基于Jvm虚拟机的一种动态语言,支持闭包、DSL等特性。Gradle脚本使用Groovy编写。本文将在此处简单介绍Groovy的语法。、
单独安装groovy环境只需要在https://github.com/apache/groovy/releases下载安装包,解压缩后创建环境变量 GROOVY_HOME=/opt/groovy/groovy-2.6.0
再将$GROOVY_HOME/bin
加入到PATH环境变量中。
或者使用如下命令:
apt install curl zip unzip
curl -s get.sdkman.io | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"
sdk install groovy
使用gvm来管理groovy版本。
$ gvm install groovy
$ gvm install groovy 2.1.9
$ gvm use groovy 2.2.0
$ gvm uninstall groovy 2.1.9
$ gvm list groovy
Groovy 和Java语法很相似,此处挑选一些基础特征作对比。
变量
class First {
static void main(String[] args) {
String a = 'Hello Single'
String b = "Hello Double"
def str1 = '单引号'
def str2 = "双引号"
println(a)
println "双引号有运算能力${a}"
println '单引号没有运算能力${b}'
}
}
(1) Groovy中结尾分号不是必须的,单引号和双引号都是字符串,区别在于双引号可以进行表达式计算。${a+b}
或者 ${a
} 只有一个变量时可以省略括号。
(2)Groovy中可以指明类型声明变量,也可以使用def 声明变量,具体类型由对象决定。
(3)脚本中声明的变量默认都是public修饰的。
数组
Groovy 中使用[ ] 创建数组,数组需要指明类型
String[] strings = ["aaa", "bbb", "ccc","ddd","eee"]
def ints = [1, 2, 3, 4] as int[];
println(strings)
println(ints)
println(strings[-1])
println(strings[0,-1])
println(strings[1..2])
[1]
取出指定位置的一个元素,返回单个元素。
[0,2,6,8,-1]
取出指定位置的多个元素,返回数组列表。
[1..6]
取出索引1 到索引6 的所有元素,返回数组列表。
数组遍历可以使用each方法,使用闭包作为参数,it是默认的遍历数据项。
strings.each {
println(it)
}
List
Groovy的List和数组很像,区别在于List不用指定元素类型,一个列表可以包含多种类型的元素。还可以使用<<
向列表内添加元素。
ArrayList arrayList =["name",23,true,22.33333]
LinkedList linkedList = ["name",23,true,22.33333]
List list = ["aaa",linkedList,22]
def list2 = ['list2','bbb',arrayList,list,linkedList]
list2 << 3
list2 << arrayList
其他元素访问方式和遍历方式和数组一样。
Map
map存储key-value 形式数据,使用:连接key-value,使用,
作为分隔符。
map.[‘key’] 或者 map.key 访问元素
基本使用如下:
def map1 = ["key": 34, "key2": "value", 34: 333]
map1["key3"] = 44
def key4 = "key4"
map1[key4]=55
println(map1)
println(map1["key2"])
println(map1.key2)
map1.each {
println(it.key + " " + it.value)
}
方法
Groovy中的方法很灵活
def mothe1(String a, b) {
println(a)
println(b)
"${a} ----- ${b}"
}
void method2() {
println("method2")
}
使用def
定义方法,无需指定返回类型,如果没有指定return语句则默认使用最后一个表达式的值作为返回值。当没有返回类型时使用void
方法入参可以指定类型,也可以不指定类型。
def first = new First();
def result
result = first.mothe1("aaa", 34)
result = first.mothe1 "aaa",34
println(result)
first.method2()
有参时方法调用可以省略掉( )
无参时不能省略。
类
在一个Groovy脚本中可以定义多个public 类,且方法和类默认就是public的。
class Car {
public def name
String company
float price
}
编译后得到Car.class文件,当成员变量没有访问修饰符时,会自动生成set 和get 方法。
public class Car implements GroovyObject {
public Object name;
private String company;
private float price;
@Generated
public Car() {
CallSite[] var1 = $getCallSiteArray();
super();
MetaClass var2 = this.$getStaticMetaClass();
this.metaClass = var2;
}
@Generated
public String getCompany() {
return this.company;
}
@Generated
public void setCompany(String var1) {
this.company = var1;
}
@Generated
public float getPrice() {
return this.price;
}
@Generated
public void setPrice(float var1) {
this.price = var1;
}
}
Groovy 中可以在没定义成员变量时,使用访问成员变量的方式调用get方法。
class People {
String name
int getAge() {
return 18;
}
}
People p = new People()
print(p.age)
所以p.age 是调用方法,而不是访问成员变量。
闭包
闭包是DSL的基础,是groovy的一个很重要的特性,可以将一段代码作为参数传入到方法中,java8中使用lambda实现闭包的功能。
定义:闭包其实就是一段花括号包围的代码块;
{ [(参数1,参数2)->] 运行代码 }
参数列表使用()包围,当只有一个参数时可以省略括号,当没有参数时可以省略->
;
groovy规定闭包只有一个参数时,可以不自己定义,使用it
作为参数。
groovy规定如果方法最后一个参数为闭包,则可以将闭包放到参数列表外部。
闭包内可以访问脚本中定义的变量。
// 定义需要闭包参数的方法
def runClosure(len,Closure closure) {
for (int i in 1..len) {
closure(i)
}
}
// 定义闭包作为变量
def a = { b -> println("我是单独实现的闭包:${b}") }
// 调用方法传入闭包参数
runClosure(10,a)
runClosure.call(10,a)
// 将末尾的闭包参数放置参数列表外部
runClosure(10) { b -> println("调用时实现的闭包:${b}") }
好玩的来了,上面的方法需要len 和 closure两个参数,如果这个方法只需要一个closure 类型的参数呢?
def startClosure(code) {
for (int i in 1..5) {
code(i)
}
}
// 使用自定义的参数作为入参
startClosure { i -> println "结果为:${i * i + 1}" }
// 使用默认的it参数作为入参
startClosure {
println "结果为:${it * it +1}"
}
是不是很熟悉,以上就是在gradle脚本中大量见到的闭包使用方式。
闭包委托
Closure对象中有三个属性,thisObject、owner、delegate
thisObject:指向定义闭包时所在的类或者实例对象。如果闭包是在脚本中创建,则this指向脚本类实例对象;如果闭包是在实例对象方法中创建,那this指向实例对象;如果是闭包嵌套创建的闭包,那也指向实例对象。
owner:和this类似,区别在于当在闭包A中创建闭包B,指向的是闭包A。
delegate:默认情况下和owner相同,我们也可以创建闭包后将其指向第三方实例对象。
class ClassC {
def test(){
println("******************************")
println("ClassC "+this)
def closureA = {
println("closure A this " + thisObject)
println("closure A owner " + owner)
println("closure A delegate " + delegate)
def closureB = {
println("closure B this " + thisObject)
println("closure B owner " + owner)
println("closure B delegate " + delegate)
def closureC = {
println("closure C this " + thisObject)
println("closure C owner " + owner)
println("closure C delegate " + delegate)
}
closureC()
}
closureB()
}
closureA()
}
}
ClassC c = new ClassC();
c.test()
当在闭包内调用一个属性或者一个方法时,会依次在this->owner->delegate
中查找是否有对应的属性或方法。当然这个顺序是可变的需要按如下方式配置
closure.setResolveStrategy(Closure.DELEGATE_FIRST)
- Closure.OWNER_FIRST,默认策略,首先从owner上寻找属性或方法,找不到则在delegate上寻找。
- Closure.DELEGATE_FIRST,和上面相反。首先从delegate上寻找属性或者方法
- Closure.OWNER_ONLY,只在owner上寻找,delegate被忽略。
- Closure.DELEGATE_ONLY,和上面相反。只在delegate上寻找,owner被忽略。
- Closure.TO_SELF,高级选项,让开发者自定义策略。
3.Gradle项目结构
通常项目结构都是由总到分的树状结构,Gradle项目也是如此。
settings.gradle
位于工程目录下,进行工程数的初始化和配置工作。一个工程可以包含多个project,settings.gradle 文件中声明了根工程名称、包含的子projet 及其目录。
// 根工程名称
rootProject.name = 'android-gradle-book-code'
// 子projet2
include ':example02'
project(':example02').projectDir = new File(rootDir, 'chapter01/example02')
// 子project3
include ':example03'
project(':example03').projectDir = new File(rootDir, 'chapter01/example03')
当不指定子工程目录时,默认使用当前setting.gradle同级目录下子工程同名的目录作为子工程目录。
build.gradle
每个project目录下都有一个build.gradle 文件,是该project构建的入口,可配置版本、需要的插件、依赖库。
当然根工程目录下也有一个build.gradle文件,可以在此设置全局的仓库入口,全局可用的插件等。如下就是
buildscript {
repositories {
maven { url "https://jitpack.io" }
jcenter()
}
dependencies {
classpath 'org.jacoco:org.jacoco.core:0.7.4.201502262128'
}
}
allprojects {
repositories {
maven { url "https://jitpack.io" }
jcenter()
}
}
subprojects {
}