Gradle Task 学习

2020-12-11  本文已影响0人  刘景昌

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")
}

上一篇 下一篇

猜你喜欢

热点阅读