一個 Task 是 Gradle 里項目構建的原子執行單元,Gradle 通過將一個個Task串聯起來完成具體的構建任務,每個 Task 都屬于一個 Project。關于 Task 的具體定義可查看官方文檔Gradle Task API。
1. 在Gradle里定義Task
在 build.gradle 里可以通過 task 關鍵字來創建Task:
task myTask
task myTask { configure closure }
task myTask(type: SomeType)
task myTask(type: SomeType) { configure closure }
我們來試驗一下,新建一個 build.gradle 文件,在里面創建2個最簡單的task:
task myTask1 {
println "configure task1"
}
task myTask2 {
println "configure task2"
}
執行其中一個task:gradle myTask1
> Configure project :
configure task1
configure task2
上面定義了2個 task :myTask1、myTask2,但是當我們執行 myTask1 時,發現2個 task 括號內部的代碼都被執行了。括號內部的代碼我們稱之為配置代碼,在 gradle 腳本的配置階段都會執行,也就是說不管執行腳本里的哪個任務,所有 task 里的配置代碼都會執行。這似乎與我們的期望不一致,通常我們寫程序時調用一個方法,這個方法里的代碼才會執行,那么我們執行一個 Task 時,這個 Task 里的代碼才會被執行才對啊。顯然 Gradle 里是不一樣的,這個問題就涉及到 Task Action 的概念了。
2. Task Actions
一個 Task 是由一序列 Action (動作)組成的,當運行一個 Task 的時候,這個 Task 里的 Action 序列會按順序依次執行。前面例子括號里的代碼只是配置代碼,它們并不是 Action ,Task 里的 Action 只會在該 Task 真正運行時執行,Gralde 里通過 doFirst、doLast 來為 Task 增加 Action 。
- doFirst:task執行時最先執行的操作
- doLast:task執行時最后執行的操作
task myTask1 {
println "configure task1"
}
task myTask2 {
println "configure task2"
}
myTask1.doFirst {
println "task1 doFirst"
}
myTask1.doLast {
println "task1 doLast"
}
myTask2.doLast {
println "task2 doLast
}
同樣執行myTask1:gradle myTask1,這次的結果如下:
> Configure project :
configure task1
configure task2
> Task :myTask1
task1 doFirst
task1 doLast
從上面例子中可以看到,所有 Task 的配置代碼都會運行,而 Task Actions 則只有該 Task 運行時才會執行。
3. doLast等價操作
doLast有一種等價操作叫做leftShift,leftShift可以縮寫為 << ,下面幾種寫法效果是一模一樣的:
myTask1.doLast {
println "task1 doLast"
}
myTask1 << {
println "task1 doLast<<"
}
myTask1.leftShift {
println "task1 doLast leftShift"
}
需要注意的是 << 操作符,它只是一種 Gradle 里的語法糖而已,不要被這種寫法迷惑了。
4. 創建Task的幾種常見寫法
task myTask1 {
doLast {
println "doLast in task1"
}
}
task myTask2 << {
println "doLast in task2"
}
//采用 Project.task(String name) 方法來創建
project.task("myTask3").doLast {
println "doLast in task3"
}
//采用 TaskContainer.create(String name) 方法來創建
project.tasks.create("myTask4").doLast {
println "doLast in task4"
}
project.tasks.create("myTask5") << {
println "doLast in task5"
}
初次接觸這些寫法,頭都是大的,Gradle太靈活了,個人覺得記住最常用的即可,看到類似寫法能看懂就行了。
5. 創建Task的參數介紹
在 Gradle 中定義 Task 的時候,可以指定更多的參數,如下所示:
參數名 | 含義 | 默認值 |
---|---|---|
name | task的名字 | 必須指定,不能為空 |
type | task的父類 | 默認值為org.gradle.api.DefaultTask |
overwrite | 是否替換已經存在的同名task | false |
group | task所屬的分組名 | null |
description | task的描述 | null |
dependsOn | task依賴的task集合 | 無 |
constructorArgs | 構造函數參數 | 無 |
我們來測試下:
task myTask1 << {
println "doLast in task1"
}
task myTask2 << {
println "doLast in task2"
}
task myTask3 << {
println "doLast in task3, this is old task"
}
task myTask3(description: "這是task3的描述", group: "myTaskGroup", dependsOn: [myTask1, myTask2], overwrite: true) << {
println "doLast in task3, this is new task"
}
執行 gradle myTask3,結果如下:
> Task :myTask1
doLast in task1
> Task :myTask2
doLast in task2
> Task :myTask3
doLast in task3, this is new task
執行命令 gradle -q tasks --all,查看下 task 信息,節選我們創建的 task 信息如下:
MyTaskGroup tasks
------------
myTask3 - 這是task3的描述
Other tasks
-----------
myTask1
myTask2
上面例子中創建了2個名為 myTask3 的 task,但是后一個將前一個替換掉了,在分組信息里多了個一個名為 MyTaskGroup 的分組,其他沒有命名分組的統一歸到 Other 這個分組里去了。
我們再來看看 type 參數怎么個用法,在 Gradle 中通過 task 關鍵字創建的 task,默認的父類都是 org.gradle.api.DefaultTask,這里定義了一些 task 的默認行為。看看下面這個例子:
//自定義Task類,必須繼承自DefaultTask
class SayHelloTask extends DefaultTask {
String msg = "default name"
int age = 18
//構造函數必須用@javax.inject.Inject注解標識
@javax.inject.Inject
SayHelloTask(int age) {
this.age = age
}
//通過@TaskAction注解來標識該Task要執行的動作
@TaskAction
void sayHello() {
println "Hello $msg ! age is ${age}"
}
}
//通過constructorArgs參數來指定構造函數的參數值
task hello1(type: SayHelloTask, constructorArgs: [30])
//通過type參數指定task的父類,可以在配置代碼里修改父類的屬性
task hello2(type: SayHelloTask, constructorArgs: [18]) {
//配置代碼里修改 SayHelloTask 里的字段 msg 的值
msg = "hjy"
}
執行這2個 task 查看運行結果如下:
> Task :hello1
Hello default name ! age is 30
> Task :hello2
Hello hjy ! age is 18
上面這個例子中,演示了如何自己創建一個 Task 類,這里只是一些最簡單的用法,每個 Task 應該還有輸入、輸出等等,且待下章分解。
官方資料
Project API
TaskContainer API
Task API
系列文章
Android Gradle學習(一):Gradle基礎入門
Android Gradle學習(二):如何創建Task
Android Gradle學習(三):Task進階學習
Android Gradle學習(四):Project詳解
Android Gradle學習(五):Extension詳解
Android Gradle學習(六):NamedDomainObjectContainer詳解
Android Gradle學習(七):Gradle構建生命周期
Android Gradle學習(八):統計Task執行時長
Android Gradle學習(九):一些有用的小技巧