Gradle系列学习:初识Gradle之Groovy基础

1,231 阅读6分钟

原文地址

一 前言

Gradle官网

官方文档,可当做字典查阅

Gradle是Android的构建工具,AndroidStudio的build是通过Gradle来实现的。不少安卓领域的技术如:插件化、热修复、构建系统等,都需要借助Gradle完成。

Groovy是一门jvm语言,功能强大细节多,全部学习收益小。作为一门DSL(特定领域语言)语言,只限于某个特定领域使用,可以理解成Gradle是用groovy语言实现的一个框架。

学习Gradle主要需要掌握下面三种语言

  1. Groovy语言
  2. Gradle DSL
  3. Android DSL

Groovy的优势:作为一门jvm语言,最终编译成class文件然后在jvm上执行,支持所有Java的特性,完全可以混写Java和Groovy,不同点可参考文档,不需要过分纠结;Groovy提供了更加灵活简单的语法、大量的语法糖以及闭包特性。学习也可部分参考W3School快速预览了解,或者阅读下面的基础语法进行大体掌握。

既然Gradle是用groovy语言实现的,下面我们自然要先学习groovy的基本语法。

二 Groovy基础语法

2.1 变量和方法

变量和fang均使用def 关键字声明:

def int a = 1;
def String b = "hello world";
 
def int hello() {
   println ("hello world");
   return 1;
}

现在我们如何执行这一段Groovy代码呢?当然我们可以在官网下载地址下载最新的gradle版本,解压、安装、添加环境变量...

但是作安卓开发者而言,或许更方便的选择是利用Android Studio中已有的环境,快速地测试代码。

打开Andriod Studio的某个项目,在Gradle Scripts目录下打开项目的build.gradle,将下面一段代码粘贴到文件末尾:

task(myGroovyTestFun).doLast {
    println "start execute myGroovyTestFun"
    println hello()
}
 
def int a = 1;
def String b = "hello world";
 
def int hello() {
    println ("hello world");
    return 1;
}

此刻打开Andriod Studio的Terminal,输入命令:

./gradlew myGroovyTestFun

这样就可以方便快速地运行我们的groovy代码,结果如下:

> Task :myGroovyTestFun
start execute myGroovyTestFun
hello world
1

是不是很方便!

我们回顾下上面的变量和方法的写法,是不是和java几乎没有区别,只不过多了def关键字!

对,但是相比java,Groovy中有很多东西可以省略:

  • 分号可省略
  • 变量的类型、方法的返回值可省略
  • 方法调用时,括号可省略
  • 方法中的return可省略
  • 方法的返回类型可省略
  • 方法有返回类型,def关键字可省略

基于以上的原则,上面的代码可以写成如下形式:

def a = 1;
def b = "hello world"; // 省略变量类型
 
// 省略def、println省略括号
int hello() {
   println "hello world";
   return 1;
}

注意:Groovy类型可以动态推断,但Groovy仍是强类型的语言,类型不匹配会报错;

2.2 Groovy的数据类型

在Groovy中,数据类型有:

  • Java中的基本数据类型和对象
  • Closure(闭包)
  • 加强的List、Map等集合类型
  • 加强的File、Stream等IO类型

基本数据类型和对象和Java中的一致,只不过Gradle中的对象默认的修饰符为public。

类型可以显示声明:

String b = "hello world"

也可以用 def 来声明,用 def 声明的类型Groovy将会进行类型推断。

def b = "hello world"

下面主要说下String、闭包、集合和IO等。

2.2.1 String

String的特色在于字符串的拼接,比如:

task(myGroovyTestFun).doLast {
    println "start execute myGroovyTestFun"
    hello()
}
 
def hello() {
    def a = 1
    def b = "hello world"
    def c = "a=${a}, b=${b}"
    println c
}

输出:

> Task :myGroovyTestFun
start execute myGroovyTestFun
a=1, b=hello world

2.2.2 Closure(闭包)

Groovy中闭包是一种特殊的数据类型,闭包可以作为一个变量、一个方法的参数or返回值。

如何声明闭包?

{ parameters ->
   code
}

闭包可以有返回值和参数,当然也可以没有。举例:

def test1 = { int a, String b ->
    println "a=${a}, b=${b}, I am a closure!"
}
 
// 这里省略了闭包的参数类型
def test2 = { a, b ->
    println "a=${a}, b=${b}, I am a closure!"
}
 
def test3 = { a, b ->
    a + b
}
 
task(myGroovyTestFun).doLast {
    println "start execute myGroovyTestFun"
    test1(100, "Lucas")
    test2.call(100, 200)
    println test3(100,200)
}

上面定义了三个闭包,每个闭包的调用方法都是call()方法,闭包的传参可通过call方法传入。在Terminal中输入命令:./gradlew myGroovyTestFun,得到结果:

> Task :myGroovyTestFun
start execute myGroovyTestFun
a=100, b=Lucas, I am a closure!
a=100, b=200, I am a closure!
300

另外,如果闭包不指定参数,那么它会有一个隐含的参数

// 这里省略了闭包的参数类型
def a = [5,'hello','world',false]
 
def b ={
 println(it)
 }
 
a.each(b)

简单用法介绍如上,如果遇到问题可先查询Groovy的文档:

www.groovy-lang.org/api.html

docs.groovy-lang.org/latest/html…

2.2.3 List和Map

Groovy中的List、Map、Set等集合可视为java中集合类的加强版。

List操作和java几乎一致,注意的是groovy中List添加新元素可用左移位操作符<<:

def emptyList = []
 
def test = [1, 'hello','world', true]
test << 200
test[1] = 2
 
println test[0]

List操作符<<,左移位表示向List中添加新元素,这一点从文档当也能查到。

其实Map也有左移操作,这如果不查文档,将会非常费解

Map的使用类似:

def emptyMap = [:]
def user = ["age":18, "name":"Lucas"]
test["age"] = 28
test.age= 38

对集合类,如果我们传递给闭包的是一个参数,闭包就把每一项作为参数;如果我们传递闭包2个参数,闭包把key和value作为参数:

def emptyMap = [:]
def test = ["age":18, "name":"Lucas"]
 
test.each { key, value ->
   println "two parameters, find [${key} : ${value}]"
}
 
test.each {
   println "one parameters, find [${it.key} : ${it.value}]"
}

2.2.4 List和Map

在Groovy中,文件访问要比Java简单的多,不管是普通文件还是xml文件。

根据File的eachLine方法,我们可以写出如下遍历代码,可以看到,eachLine方法也是支持1个或2个参数的,

def file = new File("test.txt")
println "read file using two parameters"
file.eachLine { line, lineNo ->
   println "${lineNo} ${line}"
}
 
println "read file using one parameters"
file.eachLine { line ->
   println "${line}"
}
 
outputs:
read file using two parameters
1 第一行
2 第二行
3 第三行
 
read file using one parameters
第一行
第二行
第三行

Groovy访问xml文件,也是比Java中简单多了。
Groovy访问xml有两个类:XmlParser和XmlSlurper,二者几乎一样,在性能上有细微的差别。

假设我们有一个xml,attrs.xml,如下所示:

<resources>
<declare-styleable name="CircleView">
 
   <attr name="circle_color" format="color">#98ff02</attr>
   <attr name="circle_size" format="integer">100</attr>
   <attr name="circle_title" format="string">renyugang</attr>
</declare-styleable>
 
</resources>

那么如何遍历它呢?

def xml = new XmlParser().parse(new File("attrs.xml"))
// 访问declare-styleable节点的name属性
println xml['declare-styleable'].@name[0]
// 访问declare-styleable的第三个子节点的内容
println xml['declare-styleable'].attr[2].text()
 
outputsCircleView
renyugang

三 Groovy中的类

Groovy中的很多语法和Kotlin非常类似,如果熟悉Kotlin,学习Groovy将会非常容易上手。

Groovy中,所有的Class类型都可以省略.class:

func(File.class)
func(File)
 
def func(Class clazz) {
}

类似Kotlin,属性的Getter/Setter方法是默认实现的,无需再写Getter/Setter方法:

class Book {
   String name
}

with 函数也类似Kotlin,会在with大括号的内部提供对象的上下文,我们可以直接使用with前面Book类的属性和方法:

Book bk = new Book() 
bk.with {
   id = 1
   name = "android art"
}

同Kotlin,Groovy中的==是java中的equals,java中的==可以用Groovy中的.is()方法:

Groovy非空判断也比java简单很多,同样可参考kotlin,用?.来代替if(bean!=null)的非空判断:

println book?.buyer?.name

在Groovy中,判断是否为真可以更简洁:

if (name != null && name.length > 0) {}
 
可以替换为:
if (name) {}

三元表达式:

def result = name != null ? name : "Unknown"
 
// 省略了name
def result = name ?: "Unknown"

在Groovy中switch方法可支持更多的参数类型:

switch (someone) {
   case "hello world": result = "is hello world"
   break
   case [4, 5, 6, 'inList']: result = "is list"
   break
   case 12..30: result = "is range"
   break
   case Integer: result = "is integer"
   break
   case Number: result = "is number"
   break
   case { it > 3 }: result = "number > 3"
   break
   default: result = "default"
}

参考文章:

Groovy官网

Gradle从入门到实战 - Groovy基础

www.jianshu.com/p/e8dec95c4…

www.w3cschool.cn/groovy/groo…