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