相关文档
http://www.groovy-lang.org/groovy-dev-kit.html
http://www.groovy-lang.org/api.html
基本复制此篇文档,我是作为笔记学习的形式做记录
https://www.cnblogs.com/leipDao/p/10385155.html
目录
Groovy学习
Groovy
是一门jvm
语言,最终编译成class文件然后在jvm
上执行,Java
语言的特性Groovy
都支持,我们可以混写Java
和Groovy
,就是在同一文件中可以混写, 注意,这里与Java
和Kotlin
可不一样,Java
和Kotlin
是可以互相调用,而不能在同一文件混写 。
Groovy
的优势是什么呢?Groovy
增强了Java
的很多功能。比如解析xml
文件,文件读写等,Groovy
只需要几行代码就能搞定,而如果用Java
则需要几十行代码,简单说就是使用Groovy
实现某些功能比Java
要少些很多代码。
基本语法
声明变量
Groovy使用def来声明变量,声明变量可以不加类型,运行的时候可以自动推断出变量类型,并且声明语句可以不加分号结尾
def i = 10
def str = "hello groovy"
def d = 1.25
声明方法
def
同样用来定义函数,Groovy
中函数返回值可以是无类型的:
//定义函数
def showName(){
"wang lei" //最后一行执行结果默认作为函数返回值,可以不加return
}
如果我们指定了函数的返回值类型,那么可以不加def
关键字:
//定义函数
String showName(){
"wang lei" //最后一行执行结果默认作为函数返回值
}
字符串
Groovy
中字符串分为三种,我们一个个来看。
单引号字符串
,单引号字符串不会对$
进行转义,原样输出
def i = 10
def str1 = 'i am $i yuan'
println str1
输出 i am $i yuan
双引号字符串
,双引号字符串会对$
号进行转义,如下:
def i = 10
def str2 = "i am $i yuan"
println str2
输出 i am 10 yuan
三引号字符串
,三引号字符串支持换行,原样输出,如下:
def str3 = '''
public static void main(){
println "miss you"
}
'''
println str3
输出
def str3 = '''
public static void main(){
println "miss you"
}
数据类型
Groovy
数据类型主要包括以下三种:
1.Java
中基本数据类型
2.增强的List
,Map
,Range
容器类
3.闭包
我们分别看一下
Java中基本数据类型
Groovy
中的所有事物都是对象。int
,double
等Java
中的基本数据类型,在Groovy
中对应的是它们的包装数据类型。比如int
对应为Integer
。比如:
def x = 23
println x.getClass().getCanonicalName()
def f = true
println f.getClass().getCanonicalName()
结果:
java.lang.Integer
java.lang.Boolean
增强的List,Map,Range容器类
List
List
:链表,其底层对应Java
中的List
接口,一般用ArrayList
作为真正的实现 类。
使用如下:
def myList = [5,'werw',true]//看到了吧,可以放任意数据,就是那么任性
myList.add(34)
//myList.add(12,55)//这样会报角标越界异常
myList[6] = true
println myList.size()
//遍历
myList.each{
println "item: $it"
}
myList.eachWithIndex {
it, i -> // `it` is the current element,`i` is the index
println "$i: $it"
}
println myList.getClass().getCanonicalName()
结果:
7
item: 5
item: werw
item: true
item: 34
item: null
item: null
item: true
0: 5
1: werw
2: true
3: 34
4: null
5: null
6: true
java.util.ArrayList
看到了吧,Groovy
中List
用起来方便多了,扩展了Java
中的一些功能。
单独说明一下,List
还有一种方式可以加入元素:<<
操作。如下:
myList << 34
刚接触是不是感觉很别扭,慢慢来,习惯就好了,对于<<
文档描述如下:
文档地址:http://www.groovy-lang.org/groovy-dev-kit.html与 http://www.groovy-lang.org/api.html 建议还是浏览一下文档,里面有很多好玩的东西
Map
直接看示例:
//Map类
def map = ['key1':true,name:"str1",3:"str3",4:"str4"]
println map.name // 相当于 map.get('name')
println map.get(4)
map.age = 14 //加入 age:14 数据项
println map.age //输出14
println map.getClass().getCanonicalName()
//遍历
map.each{
key,value ->
println key +"--"+ value
}
map.each{
it ->
println "$it.key ::: $it.value"
}
// `entry` is a map entry, `i` the index in the map
map.eachWithIndex { entry, i ->
println "$i - Name: $entry.key Age: $entry.value"
}
// Key, value and i as the index in the map
map.eachWithIndex { key, value, i ->
println "$i - Name: $key Age: $value"
}
println map.containsKey('key1') //判断map中是否包含给定的key
println map.containsValue(1) //判断map中是否包含给定的value
//返回所有
println map.findAll{
entry ->
entry.value instanceof String//value是String类型的
}
//返回第一个符合要求的
println map.find{
entry ->
entry.key instanceof Integer && entry.key > 1
} //返回符合条件一个entry
//清空
map.clear()
结果:
str1
str4
14
java.util.LinkedHashMap
key1--true
name--str1
3--str3
4--str4
age--14
key1 ::: true
name ::: str1
3 ::: str3
4 ::: str4
age ::: 14
0 - Name: key1 Age: true
1 - Name: name Age: str1
2 - Name: 3 Age: str3
3 - Name: 4 Age: str4
4 - Name: age Age: 14
0 - Name: key1 Age: true
1 - Name: name Age: str1
2 - Name: 3 Age: str3
3 - Name: 4 Age: str4
4 - Name: age Age: 14
true
false
{name=str1, 3=str3, 4=str4}
3=str3
0
Ranges
关于Ranges文档描述如下:
简单来说Ranges
就是对List
的扩展,用..
或者..<
来定义,具体使用如下:
//Range
def Range1 = 1..10//包括10
println Range1.contains(10)
println Range1.from +"__"+Range1.to
def Range2 = 1..<10//不包括10
println Range2.contains(10)
println Range2.from +"__"+Range2.to
//遍历
for (i in 1..10) {
println "for ${i}"
}
(1..10).each { i ->
println "each ${i}"
}
def years = 23
def interestRate
switch (years) {
case 1..10: interestRate = 0.076; break;
case 11..25: interestRate = 0.052; break;
default: interestRate = 0.037;
}
println interestRate//0.052
结果:
true
1__10
false
1__9
for 1
for 2
for 3
for 4
for 5
for 6
for 7
for 8
for 9
for 10
each 1
each 2
each 3
each 4
each 5
each 6
each 7
each 8
each 9
each 10
0.052
以上就是Groovy
中的容器类
Groovy中的闭包
闭包Closure
一开始接触的时候真是有点蒙圈的感觉,这是什么玩意,Kotlin
中也有这玩意,接触多了也就慢慢习惯了,其实就是一段可执行的代码,我们可以像定义变量一样定义可执行的代码。
闭包一般定义如下:
def xxx = {
paramters ->
code
}
比如,我们定义一下闭包:
def mClosure = {
p1,p2 ->
println p1 +"..."+p2
}
p1
,p2
也可以指定数据类型,如下:
//闭包定义
//->
前是参数定义, 后面是代码
def mClosure = {
String p1, int p2 ->
println p1 +"..."+p2
}
调用上述定义的闭包:
//调用 均可以
mClosure("qwewe",100)
mClosure.call("qwewe",100)
看到这里有C
经验的是不是瞬间想到函数指针了,连调用都非常像。
定义闭包我们也可以不指定参数,如不指定则默认包含一个名为it
的参数:
def hello = { "Hello, $it!" }
println hello("groovy")
结果:Hello, groovy!
关于闭包,刚接触肯定不习惯,自己一定要花时间慢慢体会,闭包在Gradle
中大量使用,后面讲Gradle
的时候会大量接触闭包的概念。
读文件
读文件有三种操作:一次读取一行,读取全部返回字节数据,数据流的形式读取,我们分别看一下:
一次读取一行:
def src = new File("/Users/yanpengfei/Desktop/in.txt")
//每次读取一行
src.eachLine{
//it就是每一行数据
it ->
println it
}
文件内容:
结果:
1
2
3
4
5
6
读取全部返回字节数据:
def src = new File("/Users/yanpengfei/Desktop/in.txt")
//一次读取全部:字节数组
def bytes = src.getBytes()
def str = new String(bytes)
println "str::"+str
结果:
str::1
2
3
4
5
6
数据流的形式读取:
def src = new File("/Users/yanpengfei/Desktop/in.txt")
//返回流,不用主动关闭
src.withInputStream{
inStream ->
//操作。。。。
println "inStream::"+inStream
}
结果:inStream::java.io.BufferedInputStream@2106a180
看到这里是不是不禁感叹:so easy!!!
。是的,Groovy
的IO
操作就是那么潇洒,任性。
写文件
写文件的操作同样很简单,我们看下将in.txt
文件拷贝到out.txt
中怎么操作:
//写数据
def des = new File("/Users/yanpengfei/Desktop/out.txt")
des.withOutputStream{
os->
os.leftShift(bytes)//左移在这里可以起到写入数据的作用
}
我们也可以逐行写入数据:
//写数据
def des = new File("/Users/yanpengfei/Desktop/out.txt")
des.withWriter('utf-8') { writer ->
writer.writeLine 'i'
writer.writeLine 'am'
writer.writeLine 'wanglei'
}
结果:
我们也可以这样写入数据:
des << '''i love groovy'''
IO
操作就是这么简单
XML解析
同样我电脑有如下xml
文档:
zhangsan
12
lisi
23
Groovy
解析xml
文档同样非常简单,我们可以像操作对象一样操作xml
:
//xml解析
def xmlFile = new File("/Users/yanpengfei/Desktop/test.xml")
def parse = new XmlSlurper()
def result =parse.parse(xmlFile)
def p0 = result.value.persons.person[0]
println p0['@id']
println p0.name
println p0.age
备注:我的Gradle版本'gradle-7.3.3-bin',找不到XmlSlurper
类所以没法做测试,后续解决了再替换这里
Json
直接看代码吧,很简单:
//Person类
class Person{
def first
def last
}
def p = new Person(first: 'wanglei',last: '456')
//转换对象为json数据
def jsonOutput = new JsonOutput()
def json = jsonOutput.toJson(p)
println(json)
//格式化输出
println(jsonOutput.prettyPrint(json))
//解析json
def slurper = new JsonSlurper()
Person person = slurper.parseText(json)
println person.first
println person.last
打印输出如下:
{"first":"wanglei","last":"456"}
{
"first": "wanglei",
"last": "456"
}
wanglei
456
好了,以上就是Groovy
的一些核心了,对于学习Gradle
掌握上面这些就差不多了。下面进入Gradle
的学习。
认识Gradle
Gradle
到底是个什么玩意?为什么要先抛出这个问题,从我经验来说,大量开发者都只是会配置Gradle
,配置这个,配置那个,至于为什么这么配置,出了问题怎么查找等等完全扒瞎,很多开发者都仅仅停留在配置这个阶段,我认为Gradle
的学习有三个层次:简单配置->
认为Gradle
是个脚本工具->Gradle
同样是编程框架。
我个人更倾向认为Gradle
是一个编程框架,其实无论你认为是框架还是脚本,只要能够为我所用即可。
Gradle
学习主要参考文档如下:
Gradle API:
https://docs.gradle.org/current/javadoc/org/gradle/api/package-summary.html
Gradle DSL:
https://docs.gradle.org/current/dsl/org.gradle.api.Project.html
Gradle
用户手册:https://docs.gradle.org/current/userguide/userguide.html
Android
插件DSL
参考:http://google.github.io/android-gradle-dsl/current/index.html
到这里可能你还有点蒙圈,一看文档这都是什么玩意啊,别着急,一步步来慢慢认识Gradle。
Gradle环境搭建
安装Gradle
开发环境很简单,参考官方文档即可:安装Gradle
安装Gradle
前最好将JDK
先升级到1.8
版本,Gradle
最新版本需要的JDK
版本为1.8
。
请自行安装好Gradle
环境。
初识Gradle
Gradle
是一个开源的构建自动化工具,既然是用于项目构建,那它肯定要制定一些规则,在Gradle
中每一个待编译的工程都称为Project
,每个Project
都可以引入自己需要的插件,引入插件的目的其实就是引入插件中包含的Task
,一个Project
可以引入多个插件,每个插件同样可以包含一个或多个Task
,关于插件和Task
我们后面还会单独细说。
比如,如下项目:
工程GradleLearn
包含三个module:app,library1,library2
。其中app
是App module
,而library1
,library2
均是library module
。
相信现在大部分都是这种多module
项目了,对于Gradle
来说这种叫做multiprojects
,看这意思是多projects
的项目,那么对于Gradle
来说有多少个项目呢?
我们可以通过gradle projects
命令来查看有多少个projects
:
这里我是在命令行里执行的。
备注:报错bash gradle command not found
解决办法:https://juejin.cn/post/6995473605966430245
报错: Android Gradle plugin requires Java 11 to run. You are currently using Java 1.8.
解决办法:https://www.cjavapy.com/article/91/
看到了吧,对于Gradle
来说有4
个project
,其中GradleLearn
叫做Root project
,其余三个moudule
均叫做Project
。
那Gradle
怎么知道有多少个Project
呢?在我们创建工程的时候在根目录下有个settings.gradle
文件,我们看下其中内容:
include ':app', ':library1', ':library2'
默认只有app
模块,之后我们新建的library1
,library2
模块都会自动包含进来,Gradle
就是通过查看这个配置文件来确定我们工程有多少了project
的,我们修改settings.gradle
文件:
include ':app', ':library1'
去掉library2
模块,然后在执行gradle projects
命令,如下:
看到了吧,已经没有library2
模块了。
好了,现在我们对settings.gradle
有了初步的认识,我们在看看build.gradle
文件的作用,工程根目录下有个build.gradle
,每个module
下也有自己的build.gradle
文件:
记得刚接触Gradle
的时候这几个build.gradle
文件真是让我蒙圈,怎么这么多,都干什么的,相信很多同学刚开始都有这疑问。
上面我们提到GradleLearn
叫做Root project
,其余三个moudule
均叫做Project
,其实在Gradle
中GradleLearn
被当做三个module
的父级project
,在父project
的build.gradle
中配置的信息可以作用在子project
中,比如根目录build.gradle
内容如下:
..........
allprojects {
repositories {
google()
jcenter()
}
}
.........
这里的意思就是配置此项目及其每个子项目的仓储库为google()
与 jcenter()
,这样我们就不用在每个子project
的build.gradle
中再单独配置了,否则我们需要为每个子project
单独配置一下需要引入的插件的仓储库。
根project
的build.gradle
文件并不是必须的,我们甚至可以删除掉,其存在的意义主要就是将子project
公共的配置提取到父build.gradle
来统一管理,是不是有点像“基类”的意思。
好了,以上只是大概了解了一下settings.gradle
与build.gradle
,都是及其简单的。
settings.gradle
与build.gradle
的本质
大家有没有想过这样一个问题为什么settings.gradle
可以include
子模块,又为什么build.gradle
可以写如下配置呢:
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.1'
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
其实我们在settings.gradle
与build.gradle
中看似配置的信息其实都是调用对应对象的方法或者脚本块设置对应信息。
对应对象是什么玩意?其实settings.gradle
文件最终会被翻译为Settings
对象,而build.gradle
文件最终会被翻译为Project
对象,build.gradle
文件对应的就是每个project
的配置。
Settings
与Project
在Gradle
中都有对应的类,也就是说只有Gradle
这个框架定义的我们才能用,至于Settings
与Project
都定义了什么我们只能查看其官方文档啊。
Settings对象
比如Settings
类中定义了include
方法:
include方法api说明为:
看到了吧,我们每一个配置都是调用对应对象的方法。
我还发现Settings
类中定义了如下方法:
include ':app', ':library1', ':library2'
def pro = findProject(':app')
println '----------------------------'
println pro.getPath()
println '----------------------------'
然后执行gradle assembleDebug
命令编译我们的项目输出如下:
输出了app
这个project
的信息。
Project对象
每个build.gradle
文件都会被翻译为对应的Project
对象,build.gradle
文件最重要的作用就是:
引入插件并配置相应信息
添加依赖信息
引入插件重要的就是引入插件中包含的tasks
,至于插件与tasks
后面会详细讲到。
那怎么引入插件呢?
Project
定义了apply
函数供我们调用:
平时我们看到的如下:
apply plugin: 'com.android.library'
最终都是调用那个的上面apply
方法。
在Project
类中有个很重要的方法,如下:
这个方法在配置完当前
project
后立刻调用,并且传给我们project
参数,我们调用试试,在根build.gradle
中添加如下代码:
afterEvaluate{
project ->
println "root module -----> $project.name"
}
app module
的build.gradle
添加如下代码:
afterEvaluate{
project ->
println "app module -----> $project.name"
}
同样,执行gradle assembleDebug
命令,打印如下:
Gradle
有它自己的规则,怎么配置,配置什么都在文档中有对应规定,我们配置xxx.gradle
都有对应的类,最终都翻译成对应对象,有问题查阅相关文档即可。
Gradle对象
在我们执行gradle
相关命令的时候,Gradle
框架会为我们创建一个gradle
对象,并且整个工程只有这一个gradle
对象,这个对象不像上面两个一样有对应文件,这个对象一般不需要我们配置什么,主要用于给我们提供一些工程信息,具体有哪些信息呢?查看文档中Gradle
类包含以下信息:
我们可以打印一些信息看看,在根build.gradle
中添加如下代码:
println "homeDir = $gradle.gradleHomeDir"
println "UserHomeDir = $gradle.gradleUserHomeDir"
println "gradleVersion = $gradle.gradleVersion"
执行gradle assembleDebug
命令打印如下信息:
gradle
对象最重要的就是在构建工程的时候加入各种回调,通过加入回调我们可以监听工程构建的各个时期,这部分后面会讲到。
好了,到这里Gradle
主要的三个类就基本介绍完了,至于每个类定义了什么属性,方法等等还需要自己去看看文档。
Gradle工作时序
Gradle
执行分为三个过程:
Initiliazation
初始化阶段只要为每个module
创建project
实例。这个阶段settings.gradle
文件会被解析执行。
Configration
这个阶段解析每个模块的build.gradle
文件,这个阶段完成后整个项目的tasks
执行顺序也就确定了并且task
准备就绪处于待执行状态,整个tasks
任务会构成一个有向无环图。
执行任务
这阶段就是按照顺序执行具体任务了。
在每个阶段我们可以通过gradle
对象添加回调监听。
我们在settings.gradle
文件与每个module
的build.gradle
文件添加如下信息:
settings.gradle:
println "settings start"
rootProject.name = "Gradle Accidence"
include ':app'
include ':mylibrary1'
include ':mylibrary2'
println "settings end"
根目录的build.gradle
通过gradle对象添加了一些回调监听
afterEvaluate{
project ->
println "root module afterEvaluate -----> $project.name"
}
gradle.beforeProject{
project ->
println "beforeProject $project.name"
}
gradle.afterProject{
project ->
println "afterProject $project.name"
}
gradle.taskGraph.whenReady {
println "taskGraph.whenReady"
}
gradle.buildFinished{
result ->
println "buildFinished"
}
app module的build.gradle:
println "app start"
afterEvaluate{
project ->
println "app module afterEvaluate -----> $project.name"
}
println "app end"
library1 module的build.gradle:
println "library1 start"
afterEvaluate{
project ->
println "library1 module afterEvaluate -----> $project.name"
}
println "library1 end"
library2 module的build.gradle:
println "library2 start"
afterEvaluate{
project ->
println "library2 module afterEvaluate -----> $project.name"
}
println "library2 end"
接下来我们执行gradle assembleDebug
命令,打印如下信息:
以上就是Gradle
构建工程的大体过程,在这个过程我们可以加入各种回调监听。
Gradle中的task
task
可以说Gradle
中很重要的部分,task
是Gradle
的执行单元,一个task
就是具体执行某一任务。
在AS
中我们一创建工程的时候就存在很多task
:
这些task
都是我们引入安卓插件帮我们自动引入的,关于插件马上就讲到了。
自定义task
我们可以定义自己的task
,在app
模块的build.gradle
中添加如下代码:
task aTask{
println ">>>>>>>>>>>>>>>>task..."
}
这样我们就定义了名称为aTask
的任务了,在AS
中同步之后我们可以看到:
由于我们没有指明分组所以这里默认属于other
分组,我们可以指定自己的分组:
task aTask(group:'myGroup'){
println ">>>>>>>>>>>>>>>>task..."
}
同步之后,如下:
上面我们说过build.gradle
对应Gradle
中的Project
类,Project
类中定义了如下方法:
正式由于Project
类中定义了上面方法,我们才可以以上面方式来创建task
任务。
我们可以通过gradle task
名称的命令来执行某一个task
任务,比如执行上述任务:gradle aTask
上述打印信息的代码是在Configure
阶段来执行的,也就是我们可以提前配置一下我们的task
,如果我们不需要配置想在执行我们task
的时候来执行一些操作,我们也可以修改代码如下:
task aTask(group:'myGroup'){
println ">>>>>>>>>>>>>>>>config..."
//任务开始执行初期执行
doFirst{
println ">>>>>>>>>>>>>>>>aTask doFirst..."
}
//任务开始执行末期执行
doLast{
println ">>>>>>>>>>>>>>>>aTask doLast..."
}
}
执行gradle aTask
命令来执行任务:
此外,有时我们也会看到如下写法:
task B << {
println 'B'
}
这种写法和如下写法都是一样效果:
task B {
doLast {
println 'B'
}
}
备注:此种方式,我测试时报错的
task B << {
println 'B'
}
task的依赖关系
task
之间可以指定依赖关系,比如指定A task
依赖B task
那么在执行A task
的时候需要先执行B task
,我们修改代码如下:
task aTask(group:'myGroup'){
println ">>>>>>>>>>>>>>>>a config..."
doFirst{
println ">>>>>>>>>>>>>>>>aTask doFirst..."
}
doLast{
println ">>>>>>>>>>>>>>>>aTask doLast..."
}
}
task bTask(group:'myGroup'){
println ">>>>>>>>>>>>>>>>b config..."
doFirst{
println ">>>>>>>>>>>>>>>>bTask doFirst..."
}
doLast{
println ">>>>>>>>>>>>>>>>bTask doLast..."
}
}
//这里指定aTask 依赖于bTask
aTask.dependsOn bTask
运行结果:
我们也可以创建task
的时候就直接指定依赖:
//通过dependsOn指定依赖
task aTask(group:'myGroup', dependsOn: ["bTask"]){
println ">>>>>>>>>>>>>>>>a config..."
doFirst{
println ">>>>>>>>>>>>>>>>aTask doFirst..."
}
doLast{
println ">>>>>>>>>>>>>>>>aTask doLast..."
}
}
task bTask(group:'myGroup'){
println ">>>>>>>>>>>>>>>>b config..."
doFirst{
println ">>>>>>>>>>>>>>>>bTask doFirst..."
}
doLast{
println ">>>>>>>>>>>>>>>>bTask doLast..."
}
}
运行结果:
二者同样效果
我们也可以定义task
类,此类需要继承DefaultTask
:
class IncrementTask extends DefaultTask {
@Input
String msg = 'default'
IncrementTask() {
group '自定义任务' //指定任务的分组
description '任务描述'//指定描述
}
@TaskAction
void run() {
println "IncrementTask __$msg"
}
}
上面用@TaskAction
标注方法run()
,这样我们在执行任务的时候会调用run()
方法。
接下来我们可以通过如下方式创建实例:
task increment2(type: IncrementTask) {
msg = 'create task'
}
创建task的时候我们可以指定type
,也就是指定其父类,如果我们不制定默认为DefaultTask
的子类。
我们也可以通过如下方式创建:
tasks.create('increment1', IncrementTask){
msg = 'tasks.create'//重新指定msg信息
}
这里我在说一下查文档的重要性,tasks
是什么鬼?由于我们是在build.gradle
中使用的,其对应Project
类,所以我们去Project
类中查一下,属性描述有对其描述:
原来tasks
是一个属性,点进去看一下:
其对应的是TaskContainer
类,我们还需要再看一下这个类都包含什么:
看到了吧,这个类中包含各种create
方法用来创建task
任务。
好了,task
就说这么多,有什么问题希望你自己去查文档解决,比如创建的时候可以指定type
,那还可以指定其余的信息吗?都可以指定什么信息,这些文档中都有描述。
Gradle中任务的增量构建
作为构建工具我们要防止做重复工作。例如AS
编译出APK
文件,如果我们已经编译出了APK
文件,再次编译的时候如果我们没有删除APK
文件并且代码资源等都没变化那么就没必要在重新走一遍流程执行各个task任务最重输出APK
文件,中间的任务都可以跳过,这样可以提升效率缩短编译时间。
Gradle
是通过增量构建的特性来支持这个功能的。
Gradle
在执行任务的时候会检查任务的输入输出是否有变化,如果任务的输入输出均没有变化则认为任务是up-to-date
的,会跳过任务不去执行它,任务至少有一个输出否则增量构建不起作用。
我们改造IncrementTask
,使其成为可以增量构建的任务,指明其输入输出:
class IncrementTask extends DefaultTask {
@Input //指明输入
String msg = 'default'
@OutputFile //指明输出
File file
IncrementTask() {
group '自定义任务'
description '任务描述'
}
@TaskAction
void run() {
println "IncrementTask __$msg"
}
}
我们在创建任务的时候指明其输入输出:
tasks.create('increment1', IncrementTask){
msg = 'tasks.create1'//重新指定msg信息
file = file('path.txt')
}
我们在第一次执行任务的时候,输出如下:
执行了run
方法输出相应信息,接着我们再次执行:
看到了吧,没有执行run
方法,并且提示:up-to-date
。
我们也可以关闭任务的增量构建,使其每次执行的时候都会执行run
方法:
class IncrementTask extends DefaultTask {
@Input //指明输入
String msg = 'default'
@OutputFile //指明输出
File file
IncrementTask() {
group '自定义任务'
description '任务描述'
outputs.upToDateWhen { false }//返回false关闭增量构建
}
@TaskAction
void run() {
println "IncrementTask __$msg"
}
}
tasks.create('increment1', IncrementTask){
msg = 'tasks.create1'//重新指定msg信息
file = file('path.txt')
}
每次执行结果:
增量构建功能主要是为了提升编译效率,否则一个大的项目包含几十几百的任务不能每次编译都要挨个重新执行每次任务吧,这里只是简单介绍了一下Gradle
的增量构建功能,详细学习可以自己查阅文档看一下。
自定义插件
暂不学了,学一下groovy语法,解决pod问题,后面有时间再学习插件