Gradle Learning

#1. Groovy

Groovy是一种动态语言。语言与Java相通,又像一种脚本语言。Groovy会先将Code编译成Java类字节码,然后通过JVM来执行。

###搭建开发环境
groovy

###前提语法

  • 注释标记和Java一样,支持//或者/**/
  • Groovy语句可以不用分号结尾
  • Groovy支持动态类型,即定义变量的时候可以不指定类型。Groovy中,变量定义可以使用关键字defdef不是必须的,但是为了代码清晰,建议还是使用def关键字。
  • 函数定义时,参数的类型可以不指定。
  • Groovy中函数的返回值也可以是无类型的。但必须使用def关键字。如果指定了函数返回类型,则可不必加def关键字来定义函数。无类型的函数的最后一行代码的执行结果就是本函数的返回值。

    1
    //无类型的函数定义,必须使用 def 关键字 def nonReturnTypeFunc(){ last_line //最后一行代码的执行结果就是本函数的返回值 } //如果指定了函数返回类型,则可不必加 def 关键字来定义函数 String getString(){ return "I am a string" }
  • Groovy可以不使用return xxx来返回函数结果。则代码的最后一行的结果作为返回值。如果指定了函数返回类型,则应返回正确的类型。如果使用def设置为动态类型,就可以返回任何类型。
  • Groovy对字符串的支持,充分吸收脚本语言特点。

    • 单引号''中的内容严格对应Java中的String,不对$符号进行转义。

      1
      def singleQuote='I am $ dolloar' //输出就是 I am $ dolloar
    • 双引号""中的内容和脚本语言处理有点像,如果符号中有$号的话,则它会$表达式先求值。

      1
      2
      3
      def doubleQuoteWithoutDollar = "I am one dollar" //输出 I am one dollar
      def x = 1
      def doubleQuoteWithDollar = "I am $x dolloar" //输出 I am 1 dolloar
    • 三个引号'''xxx'''中的字符串支持随意换行,比如

      1
      2
      3
      4
      def multiLines = ''' begin
      line 1
      line 2
      end '''
  • Groovy中函数调用的时候还可以不加括号。虽然写代码的时候,对于函数调用可以不带括号,但是Groovy经常把属性和函数调用混淆,所以建议只有在常用Groovy API 调用时省略括号。如:

    1
    println("test") ---> println "test"

Groovy中的数据类型

比较重要的几种:

  1. Java中的基本数据类型
  2. Groovy中的容器类
  3. 闭包(非常重要)

根据 Groovy 的原则,如果一个类中有名为 xxyyzz 这样的属性(其实就是成员变量), Groovy 会自动为它添加 getXxyyzz 和 setXxyyzz 两个函数,用于获取和设置 xxyyzz 属性值。

#####基本数据类型
Groovy中所有的事物都是对象。所int, boolean等Java中的基本数据类型,在Groovy Code中都对应于Java中包装类。

#####容器类
容器类共三种,最重要的是了解它们的用法:

  • List:链表,底层对应Java中的List接口,一般用ArrayList作为真正的实现类。
  • Map:键值表,其底层对应Java中的LinkedHashMap。
  • Range:范围,它其实就是List的一种扩展。

1. List类

List变量由[]定义,元素可以是任何对象如:

1
def aList = [5, ‘string’, true]

变量存取:可以直接通过索引存取,而且不用担心索引越界。如果索引超过当前链表长度,List会自动往该索引添加元素。

2. Map类

Map变量由[:]定义,比如

1
def aMap = ['key0':'value1', 'key1':true]

定义时,:左边是key,右边是value。key必须是字符串,value可以是任何对象。key可以用''""包起来,也可以不用引号包起来,但会被直接处理为相应的字符串:

1
2
//key0, key1会被处理为字符串“key1”和“key2”
def aNewMap = [key0:"value", key1:true]

如果不适用引号包起来有时会与变量产生混淆,如:

1
2
//key1会被处理成“key0”,而不是“wo”
def key0="wo" def aConfusedMap=[key0:"who am i?"]

如果要适用变量表示的“wo”则需要适用()来达到目的:

1
def aConfusedMap=[(key1):"who am i?"]

Map元素的存取:

1
2
3
4
5
6
7
//这种表达方法好像 key 就是 aMap 的一个成员变量一样
println aMap.keyName
//这种表达方法更传统一点
println aMap['keyName']
//为 map 添加新元素 aMap.anotherkey = "i am map"

3. Range类

Range是Groovy对List的一种扩展,变量定义和大体的适用方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
//Range 类型的变量由begin值+两个点+end值表示左边这个aRange包含1,2,3,4,5这5个值
def aRange = 1..5
//如果不想包含最后一个元素,则可以写为如下形式,包含 1,2,3,4 这 4 个元素 def aRangeWithoutEnd = 1..<5
println aRange.from println aRange.to
```
#####闭包
***1. 闭包概念***
闭包( Closure ),是Groovy中非常重要的一种概念。可以视为一种数据类型,它代表了一段可执行的代码(类似于回调,从C/C++的角度看,类似于函数指针)。
定义格式有两种(有无`->`),闭包是一段可执行代码,需要`{}`包含起来

//包含 -> 符号
def foo0 = {params -> code}
//无->符号,纯code
def foo1 = {code}

1
2
定义举例:

def aClosure = {
//这个箭头很关键。箭头前面是参数定义,箭头后面是代码
String param1, int param2 ->
//这是代码,最后一句是返回值
println "this is code"
//也可以使用 return,和 Groovy 中普通函数一样
}

1
使用方法`闭包对象.call(参数)`或者`闭包对象(参数)`,举例:

//闭包对象.call(参数)
aClosure.call("this is string", 100)
//闭包对象(参数)
aClosure("this is string", 200)

1
如果闭包没有定义参数,则隐含有一个参数,这个参数名字叫做`it`,和`this`的作用类似。`it`代表闭包的参数。如:

def greeting = { "Hello, $it!" }
assert greeting('Patrick') == 'Hello, Patrick!'

//等同于:
def greeting = { it -> "Hello, $it!" }
assert greeting('Patrick') == 'Hello, Patrick!'

1
**但是,如果在闭包时使用了`->`,但未在其之前添加参数,则表示该闭包确实没有参数,也不含`it`参数!**

def noParamClosure = { -> true}

//此时如果,给该Closure传递参数则会报错!
noParamClosure("test")//Error!!!

1
2
3
4
5
***2. Closure使用的注意点***
* 1.省略圆括号
闭包在Groovy中大量使用,很多类都定义了一些函数,这些函数最后一个参数都是一个闭包,如List的each函数:

public static List each(List self, Closure closure)

1
在实际调用的时候,如果函数的最后一个参数是Closure,可以省略该函数的`()`。如:

//定义一个 List
def iamList = [1,2,3,4,5]
iamList.each{
//省略了参数的()
println it
}

1
以及:

def testClosure(int a, String b, Closure closure){
//do something

//调用闭包
closure()

}

//调用的时候,就可以省略()
testClosure 4, "test", {
println "I am in closure"
}

1
2
3
4
这有时会产生一些困惑,尤其是在无参数的时候。
* 2.如何确定Closure的参数
如前面提到的`List`的`each`函数:

public static List each(List self, Closure closure)

1
2
调用方式:

def aList = [1,2,3,4,5]
//调用each函数,只要传入一个Closure就可以了
aList.each{
println it
}

1
2
3
4
5
6
7
8
9
10
Closure的调用要联系上下文,明确调用者对Closure的调用方式(传入的参数与返回的参数)来确定Closure的参数。
所以,在使用时要熟悉API,查阅SDK。
### 脚本类、文件I/O和XML操作
**1.脚本中的import其他类**
Groovy中可以Java那样写package,然后写类。
如果不声明public/private等访问权限,Groovy中类及其比那辆默认都是public的。
**2.脚本**
使用编译命令得到class文件,然后再将class文件使用jd-gui反编译,得到java code

//path 为输出文件地址
groovyc -d path xxx.groovy
```
可以看到:

  • xxx.groovy被转换为xxx类
  • 每一个脚本都会生成一个static main函数。这样,当我们groovy xxx.groovy的时候,其实就是Java去执行main函数。
  • 脚本中的所有代码都会放到run()函数中。
  • 如果脚本中定义了函数,则函数会被定义在xxx类中

3.脚本中的变量和作用域

直接在脚本中定义变量使用def具体类型时,该变量会被实际定义为run()函数的局部变量,因此,在定义的方法中,是无法访问该变量的。可以去掉def具体类型,此时该变量将在run()函数中被作为一个属性添加到test实例对象中,此时该脚本中定义的方法可以访问该变量。但在其他的类中是无法访问该变量的。

如果真的将变量定义为类的属性,可以在变量前添加@Field标注,此时该变量将成为脚本类的成员变量,在其他地方都可以访问。

4. 文件I/O操作与XML操作
这些操作很便捷,可以参考相关使用规则进行学习。

#2. Gradle

###Gradle介绍
Gradle是一个工具,同时也是一个编程框架。使用这个工具可以完成app的编译打包等工作。

从API的角度来看待Gradle,就可以查阅SDK文档,进行编程的函数调用,而不是拘泥于记住参数配置。

###基本组件