什么是Task
Task 在 Android Gradle 的构建系统中是一个非常重要的角色,Gradle 的构建工作都是由一系列 Task 组合完成的。一个 Project 里面可以包含很多个 Task 。Task 可以理解为一个执行体,在 Project 的视角下,也可以看作是一个原子性的操作。本篇文章我会先带大家从 gradle-api 源码的角度来看Task所属位置,之后再介绍 Task 的详细用法。
源码视角下的Task
一个 Android 项目都会有一个 rootProject (在根目录),每一个 module 也会有自己的 Project ,前面说了,一个 Project 会包含很多个 Task,具体交由 Project 的 TaskContainer 管理,我们具体看源码:
public interface Project extends Comparable<Project>, ExtensionAware, PluginAware {
//...省略无关代码
TaskContainer getTasks();
}
通过getTasks()方法获取TaskContainer的实例,TaskContainer 负责管理所有的 Task 实例。
Project接口的具体实现类 DefaultProject 在构造方法里会初始化 TaskContainer ,如下,通过 services 获取TaskContainer的实例:
public DefaultProject(String name, @Nullable ProjectInternal parent, File projectDir, File buildFile, ScriptSource buildScriptSource, GradleInternal gradle, ServiceRegistryFactory serviceRegistryFactory, ClassLoaderScope selfClassLoaderScope, ClassLoaderScope baseClassLoaderScope) {
//...省略无关代码
this.services = serviceRegistryFactory.createFor(this);
this.taskContainer = (TaskContainerInternal)this.services.get(TaskContainerInternal.class);
}
我们具体看 TaskContainer 源码:
public interface TaskContainer extends TaskCollection<Task>, PolymorphicDomainObjectContainer<Task> {
@Nullable
Task findByPath(String var1);
Task getByPath(String var1) throws UnknownTaskException;
Task create(Map<String, ?> var1) throws InvalidUserDataException;
Task create(Map<String, ?> var1, Closure var2) throws InvalidUserDataException;
Task create(String var1, Closure var2) throws InvalidUserDataException;
Task create(String var1) throws InvalidUserDataException;
<T extends Task> T create(String var1, Class<T> var2) throws InvalidUserDataException;
@Incubating
<T extends Task> T create(String var1, Class<T> var2, Object... var3) throws InvalidUserDataException;
<T extends Task> T create(String var1, Class<T> var2, Action<? super T> var3) throws InvalidUserDataException;
TaskProvider<Task> register(String var1, Action<? super Task> var2) throws InvalidUserDataException;
<T extends Task> TaskProvider<T> register(String var1, Class<T> var2, Action<? super T> var3) throws InvalidUserDataException;
<T extends Task> TaskProvider<T> register(String var1, Class<T> var2) throws InvalidUserDataException;
<T extends Task> TaskProvider<T> register(String var1, Class<T> var2, Object... var3) throws InvalidUserDataException;
TaskProvider<Task> register(String var1) throws InvalidUserDataException;
Task replace(String var1);
<T extends Task> T replace(String var1, Class<T> var2);
}
TaskContainer 有一系列的方法,首先是create()系列方法,都是用来创建 Task 的,接着是 register() 系列方法,此方法会定义一个Task,但是是在需要时才会创建。findByPath()/getByPath()方法是根据路径查找Task。
接着我们看 Task 的具体定义:
public interface Task extends Comparable<Task>, ExtensionAware {
//...省略
@Internal
String getName();
@Internal
Project getProject();
@Internal
List<Action<? super Task>> getActions();
void setActions(List<Action<? super Task>> var1);
@Internal
TaskDependency getTaskDependencies();
@Internal
Set<Object> getDependsOn();
void setDependsOn(Iterable<?> var1);
Task dependsOn(Object... var1);
@Internal
String getPath();
Task doFirst(Action<? super Task> var1);
Task doFirst(Closure var1);
@Incubating
Task doFirst(String var1, Action<? super Task> var2);
Task doLast(Action<? super Task> var1);
@Incubating
Task doLast(String var1, Action<? super Task> var2);
Task doLast(Closure var1);
@Internal
@Nullable
String getGroup();
void setGroup(@Nullable String var1);
@Internal
TaskInputs getInputs();
@Internal
TaskOutputs getOutputs();
@Internal
TaskDependency getMustRunAfter();
Task finalizedBy(Object... var1);
void setFinalizedBy(Iterable<?> var1);
@Internal
TaskDependency getFinalizedBy();
}
这里我省略了一些方法,留下一些重要的来讲解。
首先是 Action相关,执行一个 Task就是执行它的 所有 Action。 像源码里 doFirst、doLast 都会接收一个闭包,然后做为 Task的一个个 Action 来执行。doFirst、doLast系列方法,顾名思义,就是在 Task的最前面、最后面执行。
group系列方法用来给当前 Task 分组,看下图:
每一个task都会有分组,如果不指定默认在 other 分组里。创建一个Task
task customTask {
doLast {
println '我是 customTask'
}
}
你会看到,创建 task 好像是通过关键字来的,其实 "task" 是 Project 类的一个函数,它内部会委托TaskContainer调用create函数创建。customTask 是参数任务名字,第二个参数是一个闭包,在groovy语法里,如果最后一个参数是闭包的时候,可以放到括号外面,然后方法的括号可以省略,这样就成了我们上面的写法。
任务依赖
任务之间是有依赖关系的,这样可以控制哪些任务优先于哪些任务执行。比如Android的 install 任务一定依赖于 package 任务进行打包生成 apk。
我们通过 dependsOn 指定当前任务需要依赖的任务,如下:
task clean(type: Delete) {
doFirst {
println '开始clean'
}
delete rootProject.buildDir
}
task customTask(dependsOn: clean) {
doLast {
println '我是 customTask'
}
}
我把 customTask 任务依赖于 clean 任务,则执行 clean 任务之前一定会先执行 customTask 任务,如下输出:
> Task :clean UP-TO-DATE
开始clean
> Task :customTask
我是 customTask
BUILD SUCCESSFUL in 0s
任务分组
任务是可以添加分组的,如果不添加,默认在other 分组里,如下是对任务添加一个分组:
def myTask = task customTask(dependsOn: clean) {
doLast {
println '我是 customTask'
}
}
myTask.group = "custom"
我们点击 sync 同步后,会在Android Studio右边栏看到 custom 分组下的task: