文章寫得很好, 可惜Gradle更新太快。 導致打開老項目時經常出錯
一個 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" }
<< 從 Gradle5 不支持, 用doLast 替換
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注解標識
Reason: A property without annotation isn't considered during up-to-date checking.
Possible solutions:
1. Add an input or output annotation.
2. Mark it as @Internal.
//自定義Task類,必須繼承自DefaultTask class SayHelloTask extends DefaultTask {
@Input String msg = "default name"
@Input 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 應該還有輸入、輸出等等,且待下章分解。
作者:雲飛揚1
鏈接:https://www.jianshu.com/p/8e89a0b8acf8
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。