Task
Task是Gradle中的最小执行单元,要学gradle那么对Task必须要了解
先看一下 Task的构造方法
Task task(String name) throws InvalidUserDataException;
Task task(Map<String, ?> args, String name) throws InvalidUserDataException;
Task task(Map<String, ?> args, String name, Closure configureClosure);
Task task(String name, Closure configureClosure);
Task task(String name, Action<? super Task> configureAction);
参数解释
name:要创建的任务的名称
args:任务创建选项
configureClosure:用于配置已创建任务的闭包
return:如果此项目中已存在具有给定名称的任务,则@将引发InvalidUserDataException。
一个简单的Task的创建
task myTask1 {
println "task1"
}
task myTask2 {
println "task2"
}
执行Task1的结果
Configure project :
task1
task2
当我们执行 myTask1 时,发现2个 task 括号内部的代码都被执行了,为什么会是这个样子呢?
下面我们就来看一下TaskActions概念
TaskActions
一个 Task 是由一序列 Action (动作)组成的,当运行一个 Task 的时候,这个 Task 里的 Action 序列会按顺序依次执行。
在括号里面的只是配置阶段需要执行的代码,所以在配置阶段括号里面的代码就已经全部执行了,而只有在执行阶段在会真正的执行Action中的代码,进行Task的执行,Gralde 里通过 doFirst、doLast 来为 Task 增加 Action
执行函数介绍
doFirst:task执行时最先执行的操作
doLast:task执行时最后执行的操作
下面是一个简单的例子
task myTask1 {
println "configure task1"
}
task myTask2 {
println "configure task2"
}
myTask1.doFirst {
println "task1 doFirst"
}
myTask1.doLast {
println "task1 doLast"
}
myTask2.doLast {
println "task2 doLast"
}
然后我们执行Task1
执行结果
image.png
这很明显的显示出来了 配置阶段和执行阶段分别所执行的内容
Task属性解析
下面有一点代码我们来看一下Task的属性
task test1 doLast {
println "task test1 last.."
}
task test2 doLast {
println "task test2 last..."
}
task test3 doLast {
println "task test3 last..."
}
task hello(type: SayHelloTask, group: "MyGroup")
//对Task进行配置
hello.configure {
println "hello task configure"
msg = "hjy"
}
//获取Task名称
println "task name is ${hello.getName()}"
//获取Task组名
println "task group is ${hello.getGroup()}"
//设是Task中的属性值
hello.setProperty("age", 70)
//获取Task中的属性值
println "task msg is ${hello.property('msg')}"
//设置依赖Task只有在task1执行完以后才会执行Task
hello.dependsOn(test1)
//设置终结者,一般用于在Task完成以后的清理工作
hello.finalizedBy(test2)
//保证执行顺序,如果两个Task同时执行,确保hello执行完以后在执行task3
hello.setMustRunAfter([test3])
//设置task的执行条件,只有在满足条件的情况下,才会执行
hello.setOnlyIf {
//只有当 age = 70 时,才会执行task,否则不会执行
return hello.property("age") == 70
}
下面我们看一下执行结果
image.png
Task增量构建
Gradle 支持一种叫做 up-to-date 检查的功能,也就是常说的增量构建。Gradle 的 Task 会把每次运行的结果缓存下来,当下次运行时,会检查输出结果有没有变更,如果没有变更则跳过运行,这样可以提高 Gradle 的构建速度。
通常,一个 task 会有一些输入(inputs)和一些输出(outputs),task 的输入会影响其输出结果,以官网中的一张图为例:
image.png
图中只一个编译java的task,他的输入有两个,一个是jdk版本号,一个是源文件,它的输出是class文件,只要jdk或者源文件其中一个有改动那么最终编译的结果肯定是不同的。当我们执行过一次编译任务后,再次运行该 task ,如果发现它的输入没有任何改变,那么它编译后的结果肯定也是不会变化的,可以直接从缓存里获取输出,这样 Gradle 会标识该 task 为 UP-TO-DATE,进而跳过该 task 的执行。
那么我们如何使用增量编译呢?
TaskInputs、TaskOutputs
个增量构建必须至少指定一个输入、一个输出。下面我们举一个例子来测试一下
//这是一个增量的Task
task test1 {
//设置inputs
inputs.property("name", "ljc")
inputs.property("age", 30)
//设置outputs
outputs.file("$buildDir/test1.txt")
doLast {
println "exec task task1"
}
}
//这是一个正常的Task
task test2 {
doLast {
println "exec task task2"
}
}
第一次执行Task1
image.png
第二次执行Task1
image.png
可以看出
并不是每次Task都被执行了 这就是增量构建
taskInputs、taskOutputs注解
当你自定义 task class 时,可以通过注解来实现增量构建,这是一种更加灵活方便的方式。我们常用的注解包括:
@Input:一个简单的输入值
@InputFile:一个输入文件,不是目录
@InputDirectory: 一个输入目录,不是文件
@InputFiles: 文件列表,包含文件和目录
@OutputFile: 一个输出文件,不是目录
@OutputDirectory:一个输出目录,不是文件
@OutputFiles: 输出文件列表
@OutputDirectories :输出目录列表
测试Task
class UserTask extends DefaultTask {
//定义输入
@Input
String username
@Input
int age
//定义输出
@OutputDirectory
File destDir;
@TaskAction
void sayHello() {
println "Hello $username ! age is $age"
}
}
task test(type: UserTask) {
age = 19
username = "hjy"
destDir = file("$buildDir/test")
}
网友评论