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

通过路径访问的方式有两种: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"
}

《Gradle 学习之任务 Task》

  1. 使用 gradle tasks 命令可以查看任务的信息,包括任务的分组和描述
    《Gradle 学习之任务 Task》
  2. 在 AS 中 Gradle Task 列表可以看见任务的分组,鼠标悬停某一任务上可以看见它的描述
    《Gradle 学习之任务 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"
	}
}

《Gradle 学习之任务 Task》

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

《Gradle 学习之任务 Task》

六、任务的启用和禁用

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

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

《Gradle 学习之任务 Task》

七、任务的 onlyIf 断言

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

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

《Gradle 学习之任务 Task》

八、任务规则

  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 不存在,无法执行..."
	}
}
  • 没有添加规则时的没有找到任务会编译失败
    《Gradle 学习之任务 Task》
  • 添加规则后的没有找到任务会根据规则执行(示例为打印信息)
    《Gradle 学习之任务 Task》

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

    原文作者:Nicholas_hzf
    原文地址: https://blog.csdn.net/Nicholas1hzf/article/details/122611974
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞