前言
这一篇我们来说说Gradle
中另外一个重要的概念Task
1.Task
的定义和配置
1.1Task
的定义
第一种:可以直接通过task
函数去定义
第二种:通过TaskContainer
就是我们上面用红框圈起来的那个,那怎么创建呢?直接调用create
方法即可
这两种方式有啥区别呢?实际上第一种方式最终也是会添加到TaskContainer
中,TaskContainer
相当于我们Task
的管理类,既然是管理类,那么就不止可以创建,我们看下它的源码
@HasInternalProtocol
public interface TaskContainer extends TaskCollection<Task>, PolymorphicDomainObjectContainer<Task> {
...
@Nullable
Task findByPath(String path);
Task getByPath(String path) throws UnknownTaskException;
<T extends Task> T create(String name, Class<T> type, Action<? super T> configuration) throws InvalidUserDataException;
TaskProvider<Task> register(String name, Action<? super Task> configurationAction) throws InvalidUserDataException;
Task replace(String name);
...
我们看完源码发现TaskContainer
主要就是查找和新增,其他我们几乎很少使用
1.2 Task
的配置
比如我们想为我们的task
配置组名和描述
第一种:我们在定义的时候直接对它进行配置
第二种:在配置代码块中调用各种配置方法
相同分组的task
会被放在一起,我们看下
那我们都能为task
配置哪些呢?我们去Task
源码看下就行了
2.Task
的执行详解
我们发现我们执行helloTask
这个task
,也会打印出helloTask2
里面的输出内容,为什么呢?很简单,因为它们都是在配置阶段执行的,那么我们怎么让他们在执行阶段执行呢?调用doFirst
或者doLast
方法
我们看下结果
首先doFirst
和doLast
确实是在执行阶段执行的.然后就是在外面执行的doFirst
或者doLast
要优先比在闭包中执行,这两个方法可以对gradle
中提供的已有的task
进行扩展
下面我们就实战下,统计我们build
的时间
思路:
- 1.定义两个变量:开始执行时间和执行结束时间,两者差值就是我们要的结果
- 2.找到第一个被执行的
task
,调用doFirst
方法,获取开始时间 - 3.找到最后被执行的
task
,执行doLast
方法,获取结束时间 - 4.两者做差
我们打印看下一共用了多长时间
3.Task
的依赖和执行顺序
3.1 Task
依赖
我们首先定义三个task
我们先执行下什么都不依赖的taskC
只输出了taskC
,后续我们会和这个作对比
我们想为我们的taskC
指定依赖该怎么做呢?
第一种:在定义的时候添加
dependsOn
,就跟我们之前添加group
一样
添加多个需要使用数组
我们执行下taskC
第二种:调用
dependsOn
方法
第三种:动态依赖
这里我们为了演示再新建几个task
然后我们通过TaskContainer
的findAll
方法找我符合我们的task
,然后taskC
依赖他们
我们执行下taskC
3.2 Task
输入输出
TaskInputs
:Task
输入类,可以是任意数据类型和文件
TaskOutputs
:Task
输出类,只能是文件或者文件夹,同时也可以作为另外Task
的TaskInputs
下面我们写一个小例子来学习下这两个方法
假设我们想输出一个xml
文件.里面的内容包括版本号和版本信息,
首先我们新建三个扩展属性:
这里我们还需要定义一个File
,就是我们的release.xml
,如果不存在我们就手动创建下
然后我们就开始实现我们的读写功能,相对应的我们需要创建两个task
,writeTask
和readTask
我们先写writeTask
我们要把我们之前定义的三个属性传给我们的task
inputs.property('versionCode', this.versionCode)
inputs.property('versionName', this.versionName)
inputs.property('versionInfo', this.versionInfo)
还要指定输出
//为task指定输出
outputs.file this.destFile
下面就开始编写真正的逻辑,这段逻辑写在doLast{}
中
task writeTask {
inputs.property('versionCode', this.versionCode)
inputs.property('versionName', this.versionName)
inputs.property('versionInfo', this.versionInfo)
outputs.file this.destFile
doLast {
// 返回一个map
def data = inputs.getProperties()
File file = outputs.getFiles().getSingleFile()
// 将map转为实体对象
def versionMsg = new VersionMsg(data)
def sw = new StringWriter()
def xmlBuilder = new MarkupBuilder(sw)
// 文件中没有内容
if (file.text != null && file.text.size() <= 0) {
// 将xml数据写入到sw中
xmlBuilder.releases { // <releases>
release { // <releases>的子节点<release>
versionCode(versionMsg.versionCode)
// <release>的子节点<versionCode>1.0.0<versionCode>
versionName(versionMsg.versionName)
versionInfo(versionMsg.versionInfo)
}
}
// 将sw里的内容写到文件中
file.withWriter { writer ->
writer.append(sw.toString())
}
} else { // 已经有其它版本信息了
xmlBuilder.release {
versionCode(versionMsg.versionCode)
versionName(versionMsg.versionName)
versionInfo(versionMsg.versionInfo)
}
def lines = file.readLines()
def lengths = lines.size() - 1
file.withWriter { writer ->
lines.eachWithIndex { String line, int index ->
if (index != lengths) {
writer.append(line + '\r\n')
} else if (index == lengths) {
writer.append(sw.toString() + '\r\n')
writer.append(line + '\r\n')
}
}
}
}
}
}
task readTask {
inputs.file destFile
doLast {
def file = inputs.files.singleFile
println file.text
}
}
然后写一个测试task
依赖这两个task
task taskTest(dependsOn: [writeTask, readTask]) {
doLast {
println '任务执行完毕'
}
}
这里有个地方要注意下,writeTask
执行顺序是要优先于readTask
的
3.3 Task
通过API
指定执行顺序
mustRunAfter
: 强行指定在某个或某些task
执行之后才执行。shouldRunAfter
: 与mustRunAfter
的作用一样,但不强制。
这里我们新建几个task
来实践下
这里我们强制执行顺序为taskX
,taskY
,taskZ
我们打乱下执行顺序看下输出结果
4.挂接到构建生命周期
这个和我们之前讲解获取构建时长类似,我们这里是项目build完执行我们自定义的task
5.Task
的类型
这个我们就需要去gradle
官网去了解下了
官网
打开官网后,找到左侧的Task types
比如我们之前说的Copy