Gradle 学习之任务 Task

news/2024/5/20 5:02:04 标签: gradle, 任务, Task, Groovy, android

目录

一、多种方式创建任务

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;

Task">

二、多种方式访问任务

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. 通过路径访问

通过路径访问的方式有两种:getfind
区别: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. 通过名称访问
通过名称访问的方式有两种:getfind
区别: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. 值得注意的是,通过路径访问任务的时候,参数值可以是路径也可以是任务名称,但是通过名称访问任务的时候,参数值就只可以是任务名称

三、任务分组与描述

  1. 任务分组就是对任务进行分类,方便我们对任务归类整理
  2. 任务描述就是对任务进行一个说明,方便他人清楚任务的用途
task task5
task5.group = BasePlugin.BUILD_GROUP
task5.description = "这是一个 build 分组的任务"
task5.doLast {
	println "group:$group,description:$description"
}

<a class=任务分组与任务描述" />

  1. 使用 gradle tasks 命令可以查看任务的信息,包括任务的分组和描述
    <a class=任务信息" />
  2. 在 AS 中 Gradle Task 列表可以看见任务的分组,鼠标悬停某一任务上可以看见它的描述
    AS Gradle <a class=Task" />

四、任务的执行分析

  1. 任务的执行其实就是任务里面一系列的 Action 的执行
// AbstractTask.java
@Override
public List<ContextAwareTaskAction> getTaskActions() {
    if (actions == null) {
        actions = new ArrayList<ContextAwareTaskAction>(3);
    }
    return actions;
}
  1. 通过源码来看任务的执行(版本号: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"
	}
}

<a class=任务的执行分析示例" />

  • 源码分析之 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

<a class=任务排序" />

六、任务的启用和禁用

enabled 属性,默认为 true 表示启用任务,置为 false 则会禁用任务

task task7
task7.doLast{
	println "Task7 执行..."
}
task7.enabled = false

<a class=任务禁用" />

七、任务的 onlyIf 断言

  1. 什么是 onlyIf 断言:就是一个条件表达式Task 类中有一个 onlyIf 方法,这个方法接收一个闭包参数根据返回值 true/false 来决定任务是执行还是跳过
  2. 示例:
task task8
task8.onlyIf{
	println "Task8 执行..."
	false
}

task task9
task9.onlyIf{
	println "Task9 执行..."
	true
}

onlyIf 断言

八、任务规则

  1. 通过第二小节的学习,我们知道了多种访问任务的方式,当我们通过任务名称来访问任务时,如果对应的任务不存在,那么就会调用我们添加的规则来处理这种情况
// 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);
}
  1. 示例:
tasks.addRule "这是任务规则的描述",{ String taskName ->
	task(taskName).doLast{
		println "$taskName 不存在,无法执行..."
	}
}
  • 没有添加规则时的没有找到任务编译失败
    没有添加规则时的没有找到<a class=任务" />
  • 添加规则后的没有找到任务根据规则执行(示例为打印信息)
    添加规则后的没有找到<a class=任务" />

整理学习自飞雪无情大佬的《Android Gradle 权威指南》和互联网资料


http://www.niftyadmin.cn/n/1252345.html

相关文章

Gradle 学习之插件介绍

目录一、Gradle 设计介绍二、Gradle 插件介绍1. 二进制插件2. 脚本插件3.应用第三方发布的插件一、Gradle 设计介绍 Gradle 的扩展性十分强&#xff0c;它本身提供基本的概念和整体的核心框架&#xff0c;其他的具体场景逻辑&#xff0c;都是以插件的形式进行扩展 Gradle 本身…

微任务与宏任务

微任务与宏任务 宏任务包括&#xff1a;setTimeout setInterval Ajax DOM事件微任务&#xff1a;Promise async/await注意&#xff1a;微任务比宏任务的执行时间要早下面请看例子 console.log(100);setTimeout(()>{console.log(200); })setTimeout(()>{console.log(201…

如何一句话激怒程序员

前言原本安静的办公室总是可以因为某个人的一两句话而变的热闹起来&#xff0c;进而发生或纯技术、或纯愤怒、或两者皆是的争吵……1、前端没有任何技术含量这是之前的一个后端的同事说的&#xff0c;当时小生内心已经在质疑他的智商了&#xff0c;不过嘴上说的是&#xff1a;你…

js数据类型判断

js数据类型判断一共有四种方法 typeof、instanceof、constructor、Object.prototype.toString.call() 下面我来为大家一一的介绍一下 1、typeof 基本数据类型中&#xff1a;Number&#xff0c;String&#xff0c;Boolean&#xff0c;undefined 以及引用数据类型中Function …

Kotlin 学习之被我一直用错的“return@forEachIndexed/return@forEach”

目录一、集合遍历二、样例问题场景三、原因四、如何实现 Kotlin forEach 与 forEachIndexed 循环中的 break 与 continue五、心得一、集合遍历 1. Java 集合遍历方式 在 Java 中我们在遍历一个集合的时候常常使用的是以下两种方式&#xff1a; for (int i 0; i < list.s…

面 5 家挂 5 家,现在找工作这么难了吗?

今年&#xff0c;由于疫情的影响&#xff0c;很多互联网企业都在缩减招聘成本。作为前端工程师&#xff0c;市场上的人才本来就很多&#xff0c;而现在的求职局面又完全是企业在挑人的状态。小丽原本一心想进大厂&#xff0c;但是在这样的情况下&#xff0c;她也有些力不从心了…

js的内存泄漏与垃圾回收机制

垃圾回收机制 浏览器的js具有自动垃圾回收机制&#xff08;GC&#xff09;&#xff0c;执行环境会管理代码在执行中所使用的内存&#xff0c;垃圾回收器会定期寻找不再使用的变量&#xff0c;释放其内存&#xff0c;垃圾回收器会按照时间间隔周期性的执行 变量的死亡 全局作…

Gradle 学习之如何配置依赖

在提倡分享与开源的时代&#xff0c;各式各样的“工具”层出不穷&#xff0c;免去了很多重头再来的冗余工作&#xff0c;我们只要利用好合适的“工具”就可以快速&#xff0c;便捷的实现目标功能&#xff0c;那么 Gradle 是如何帮助找到这些“工具”的呢&#xff1f;重点其实就…