Gradle 学习之任务 Task
Posted Nicholas_hzf
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Gradle 学习之任务 Task相关的知识,希望对你有一定的参考价值。
目录
一、多种方式创建任务
1. 以任务名称创建任务
- 示例:
// 以任务名称创建任务
def Task taskCreatedByName = task taskCreatedByName
// def Task taskCreatedByName = task(taskCreatedByName)
taskCreatedByName.doLast
println "这是一个通过任务名称创建的任务"
- 原型:
Task task(String name) throws InvalidUserDataException;
2. 以任务名称和对任务配置的 Map 对象创建任务
- 示例:
// 以任务名称和对任务配置的 Map 对象创建任务
def Task taskCreatedByNameAndMap = task taskCreatedByNameAndMap,group:BasePlugin.BUILD_GROUP
taskCreatedByNameAndMap.doLast
println "这是一个通过任务名称和对任务配置的 Map 对象创建的任务"
- 原型:
Task task(Map<String, ?> args, String name) throws InvalidUserDataException;
- Map 对象的可用配置
配置项 | 描述 | 默认值 |
---|---|---|
type | 基于一个存在的 Task 来创建,与继承差不多 | DefaultTask |
overwrite | 是否替换存在的 Task,与 type 配合使用 | false |
dependsOn | 配置任务依赖 | [] |
action | 添加到任务中的一个 Action 或者一个闭包 | null |
description | 配置任务的描述 | null |
group | 配置任务的分组 | null |
3. 以任务名称和闭包配置创建任务
- 通过 Map 对象可以进行配置的项是有限的,所以可以通过闭包的形式来对任务进行更加灵活全面的配置
- 示例:
// 以任务名称和闭包配置创建任务
task taskCreatedByNameAndClosure
doLast
println "这是一个通过任务名称和闭包配置创建的任务"
- 原型:
Task task(String name, Closure configureClosure);
4. 以任务名称、Map 参数和闭包配置创建任务
- 示例:
// 以任务名称,Map 对象和闭包配置创建任务
task taskCreatedByNameMapAndClosure,group:BasePlugin.BUILD_GROUP,
doLast
println "这是一个通过任务名称,Map 对象和闭包配置创建任务"
- 原型:
Task task(Map<String, ?> args, String name, Closure configureClosure);
5. TaskContainer 对象的 create 方法创建任务
- 使用 TaskContainer 对象创建任务的方式也较多,可以查看 Project.java 文件看看不同的创建方式,这里仅举例一种
- 示例:
// TaskContainer 对象的 create 方法创建任务
tasks.create('taskCreatedByTaskContainer')
doLast
println "这是一个通过 TaskContainer 对象创建的任务"
- 原型:
Task create(String name, Closure configureClosure) throws InvalidUserDataException;
二、多种方式访问任务
1. 以任务名称访问任务
我们创建的任务都会成为 Project 的一个属性,属性名称就是任务名称,所以可以通过任务名称来访问操作任务
task task1
task1.doLast
println "以任务名称访问任务"
2. 以访问集合元素访问任务
任务都是通过 TaskContainer 对象创建的,在 Project.java 中 tasks 就是 TaskContainer 的对象,所以可以通过 tasks 来获取对应的任务
示例代码中“[]”并不表示 tasks 是一个 Map,而是 Groovy 重载了这个操作符,跟进源码会发现最后是调用的 findByName(String name)
实现的
task task2
// TaskContainer getTasks();
tasks['task2'].doLast
println "以访问集合元素访问任务"
3. 通过路径访问
通过路径访问的方式有两种:get 与 find
区别:get 找不到任务的时候会抛出异常而 find 找不到任务时会返回 null
task task3
tasks['task3'].doLast
println "-----通过路径访问任务-----"
println tasks.findByPath(':task2')
println tasks.getByPath(':task2')
println tasks.findByPath(':task0')
println tasks.getByPath(':task0')
// TaskContainer.java
@Nullable
Task findByPath(String path);
Task getByPath(String path) throws UnknownTaskException;
4. 通过名称访问
通过名称访问的方式有两种:get 与 find
区别:get 找不到任务的时候会抛出异常而 find 找不到任务时会返回 null
task task4
tasks['task4'].doLast
println "-----通过名称访问任务-----"
println tasks.findByName('task2')
println tasks.getByName('task2')
println tasks.findByName('task0')
// println tasks.getByPath('task0')
// TaskCollection.java
// TaskContainer 继承自 TaskCollection<Task> 和 PolymorphicDomainObjectContainer<Task>
// getByName 方法来自于 TaskCollection
@Override
T getByName(String name) throws UnknownTaskException;
// NamedDomainObjectCollection.java
// TaskCollection 继承 NamedDomainObjectSet
// NamedDomainObjectSet 继承 NamedDomainObjectCollection
// findByName 方法来自于 NamedDomainObjectCollection
@Nullable
T findByName(String name);
5. 值得注意的是,通过路径访问任务的时候,参数值可以是路径也可以是任务名称,但是通过名称访问任务的时候,参数值就只可以是任务名称
三、任务分组与描述
- 任务分组就是对任务进行分类,方便我们对任务归类整理
- 任务描述就是对任务进行一个说明,方便他人清楚任务的用途
task task5
task5.group = BasePlugin.BUILD_GROUP
task5.description = "这是一个 build 分组的任务"
task5.doLast
println "group:$group,description:$description"
- 使用
gradle tasks
命令可以查看任务的信息,包括任务的分组和描述
- 在 AS 中 Gradle Task 列表可以看见任务的分组,鼠标悬停某一任务上可以看见它的描述
四、任务的执行分析
- 任务的执行其实就是任务里面一系列的 Action 的执行
// AbstractTask.java
@Override
public List<ContextAwareTaskAction> getTaskActions()
if (actions == null)
actions = new ArrayList<ContextAwareTaskAction>(3);
return actions;
- 通过源码来看任务的执行(版本号:7.0.2)
- 示例
task executeTask(type: Task6)
executeTask.doFirst
println "Task 自身执行之前执行 doFirst"
executeTask.doLast
println "Task 自身执行之后执行 doLast"
class Task6 extends DefaultTask
@TaskAction
def doSelf()
println "Task 自身执行 doSelf"
- 源码分析之 doSelf() 方法—创建任务的时候,Gradle 会解析任务中带有
@TaskAction
注解标注的方法,作为任务执行的 Action,然后通过prependParallelSafeAction(...)
方法将这个 Action 添加到 Action 的执行列表中
// AbstractTask.java
@Override
public void prependParallelSafeAction(final Action<? super Task> action)
if (action == null)
throw new InvalidUserDataException("Action must not be null!");
getTaskActions().add(0, wrap(action));
- 源码分析之 doFirst(…) 方法—永远都是在 Action 执行列表的第一位进行插入操作,重点
getTaskActions().add(0, wrap(action, actionName));
// AbstractTask.java
@Override
public Task doFirst(final Action<? super Task> action)
return doFirst("doFirst action", action);
@Override
public Task doFirst(final String actionName, final Action<? super Task> action)
hasCustomActions = true;
if (action == null)
throw new InvalidUserDataException("Action must not be null!");
taskMutator.mutate("Task.doFirst(Action)", new Runnable()
@Override
public void run()
getTaskActions().add(0, wrap(action, actionName));
);
return this;
- 源码分析之 doLast(…) 方法—永远都是在 Action 执行列表的最后进行插入操作,重点
getTaskActions().add(wrap(action, actionName));
// AbstractTask.java
@Override
public Task doLast(final Action<? super Task> action)
return doLast("doLast action", action);
@Override
public Task doLast(final String actionName, final Action<? super Task> action)
hasCustomActions = true;
if (action == null)
throw new InvalidUserDataException("Action must not be null!");
taskMutator.mutate("Task.doLast(Action)", new Runnable()
@Override
public void run()
getTaskActions().add(wrap(action, actionName));
);
return this;
五、任务排序
说是排序,其实不准确,应该说是指定任务 A 在任务 B 执行后执行,并且根据调用的 api 不一样,执行与否有可能和一定的区分
shouldRunAfter
应该在之后执行mustRunAfter
必须在之后执行
task taskA
taskA.doLast
println "TaskA 执行..."
task taskB
taskB.doLast
println "TaskB 执行..."
taskA.mustRunAfter taskB
六、任务的启用和禁用
enabled 属性,默认为 true 表示启用任务,置为 false 则会禁用该任务
task task7
task7.doLast
println "Task7 执行..."
task7.enabled = false
七、任务的 onlyIf 断言
- 什么是 onlyIf 断言:就是一个条件表达式。Task 类中有一个
onlyIf
方法,这个方法接收一个闭包参数,根据返回值 true/false 来决定任务是执行还是跳过 - 示例:
task task8
task8.onlyIf
println "Task8 执行..."
false
task task9
task9.onlyIf
println "Task9 执行..."
true
八、任务规则
- 通过第二小节的学习,我们知道了多种访问任务的方式,当我们通过任务名称来访问任务时,如果对应的任务不存在,那么就会调用我们添加的规则来处理这种情况
// DefaultNamedDomainObjectCollection.java
@Override
public T findByName(String name)
T value = findByNameWithoutRules(name);
if (value != null)
return value;
ProviderInternal<? extends T> provider = index.getPending(name);
if (provider != null)
// TODO - this isn't correct, assumes that a side effect is to add the element
provider.getOrNull();
// Use the index here so we can apply any filters to the realized element
return index.get(name);
if (!applyRules(name))
return null;
return findByNameWithoutRules(name);
- 示例:
tasks.addRule "这是任务规则的描述", String taskName ->
task(taskName).doLast
println "$taskName 不存在,无法执行..."
- 没有添加规则时的没有找到任务会编译失败
- 添加规则后的没有找到任务会根据规则执行(示例为打印信息)
整理学习自飞雪无情大佬的《android Gradle 权威指南》和互联网资料
以上是关于Gradle 学习之任务 Task的主要内容,如果未能解决你的问题,请参考以下文章