配置Gradle環境
前提:配置好Java環境
把gradle 對象的bin目錄配置到系統環境變量裏面
出現如下圖,則表示環境已經配置好了
Gradle版 hello world
創建一個build.gradle文件
添加gradle版的hello world腳本代碼
task hello{
doLast{
println 'hello world'
}
}
在控制檯輸入如下命令,編譯完成後會出現hello world字符,正是我們println輸出的
build.gradle是Gradle默認的構造腳本文件,執行gradle命令的時候,會默認加載當前目錄下的build.gradle腳本文件
這個構建腳本定義一個任務,這個任務名字叫hello,並且給任務hello添加了一個Action,它其實就是一段Groovy語言實現的閉包。doLast就意味着在Tast執行完畢後要回調doLast的這部分閉包的代碼
再看gradle -q hello這個命令,意思是要執行build.gradle腳本中定義的名爲hello的Task,-q 參數用於控制gradle輸出的日誌級別,以及哪些日誌可以輸出被看到。
如果不加-q命令,如下
是不是有點類型我們的android studio裏面的EventLog裏面的日誌
看到println ‘hello world’,它會輸出hello world,通過名字大家已經猜出來,它其實就是System.out.println(“hello world”)的簡寫方法,Gradle可以識別它,是因爲Groovy已經把println()這個方法添加到java.lang.Object,而在Groovy中,方法的調用可以省略簽名中的括號,以一個空格分開即可,所以就有了上面的寫法。說明的是,在Groovy中,單引號和雙引號所包含的內容都是字符串
Gradle 日誌
前面我們通過-q參數控制命令,Gradle的日誌級別還有其他類型,如下
要使用它們,則通過命令行參數開關控制
輸出錯誤堆棧信息 ,默認情況堆棧信息的輸出是關閉的,我們可以同如下參數打開它。這樣在我們構建失敗的時候,Gradle纔會輸出錯誤堆棧信息
使用自己的日誌調試,如果我們需要輸出一些日誌,通常情況下我們使用print系列方法,把日誌信息輸出到標準的控制檯輸出流
printl ‘輸出一個日誌信息’
除了print系列方法,也可以使用內置的logger更靈活的控制輸出不同級別的日誌信息:
logger.quiet(‘message’)
logger.error(‘message’)
logger.warn(‘message’)
logger.lifecycle(‘message’)
logger.info(‘message’)
logger.debug(‘message’)
這裏其實是調用Project的getLogger()方法阿獲取Logger對象的實例
Groovy 基礎
Groovy是基於JVM虛擬機的一種動態語言,語法和Java相似,完全兼容Java,又在此基礎上增加了很多動態類型和靈活的特性,比如支持閉包,支持DSL,可以說它是一門非常靈活的動態腳本語言
每個Gradle的build腳本文件都是一個Groovy腳本文件,你可以在裏面寫任何符號Groovy語法的代碼,而Groovy又完全兼容Java,所有你也可以在build腳本文件裏面寫任何Java代碼
字符串
添加代碼,
task printlnStr <<{
def str1='單引號'
def str2='雙引號'
println '單引號類型:'+str1.getClass().name
println '雙引號類型:'+str2.getClass().name
def name="張三"
println '單引號變量:${name}'
println "雙引號變量:${name}"
}
輸出日誌,可以看到單引號和雙引號都是String類型,但是單引號不能對字符串裏面的表達式做運算,雙引號可以直接進行表達式計算,一個美元符號緊跟一對花括號,花括號裏面放表達式,如何 {1+1}等,只有一個變量的時候可以省略花括號,如$name
通常我們在app 的build.gradle 也常常看到,如下,我們就知道SUPPORTVERSION就是一個變量,並且這裏不能用單引號表示
implementation "com.android.support:appcompat-v7:$SUPPORTVERSION"
implementation "com.android.support:cardview-v7:$SUPPORTVERSION"
集合
Groovy完全兼容了Java的集合,並且進行了擴展
List
定義一個List,訪問List集合
task printList <<{
def numList=[1,2,3,4,5];
println numList.getClass().name
println numList[1] //訪問第二個元素
println numList[-1] //訪問最後一個元素
println numList[1..3] //訪問第二個元素到第四個元素
numList.each{
println it
}
}
輸出,可以看到numList是一個ArrayList類型,訪問方式也多種,其中each方法可以方便的迭代操作,該方法接收一個閉包作爲參數,可以訪問List裏面的每個元素
定義一個Map,訪問Map集合
task printMap <<{
def map=['w':123,'h':456];
println map.getClass().name
println map['w']
println map.h
map.each{
println "key:${it.key},value:${it.value}"
}
}
方法
這個是重點了
在Java裏面調用方法是method(parm1,parm2),而在Groovy裏面,可以省略(),變成method parm1,parm2
代碼
task testMethod <<{
add(1,2)
add 1,2
}
def add(int a,int b){
println a+b
}
輸出
return可以不寫 ,Groovy中,定義有返回值的方法時,return 語句不是必需的,當沒有return時候,最後一句代碼作爲返回值
代碼
task testMethod <<{
add(1,2)
add 1,2
def result=method2 1,2
println "result:$result";
}
def add(int a,int b){
println a+b
}
def method2(int a,int b){
a+b
}
輸出
代碼塊可以作爲參數傳遞,代碼塊–一段被花括號包圍的代碼,也就是閉包。Groovy允許其作爲參數傳遞
以上面集合each方法爲例子,調用集合的each方法,傳入代碼塊
numList.each({
println it
})
//Groovy規定,如果方法的最後一個參數是閉包,可以方法方法外面
numList.each(){
println it
}
//由於方法參數括號可以省略,因此變成這樣的樣式
numList.each{
println it
}
閉包
前面說過閉包就是一段代碼塊,下面我們先自己寫一個閉包。我們定義了一個方法customEach,它只有一個參數用於接收一個閉包,那麼閉包怎麼執行呢?調用方法的時候後面跟一對括號就是執行了。
括號裏的參數就是該閉包接收的參數,
如果參數只有一個,那麼就是it變量
task testClosure <<{
customEach{
println it
}
}
def customEach(closure){
for(int i in i..10){
closure(i)
}
}
輸出
多個參數,當閉包只有一個參數是,默認就是it,當有多個參數時,就需要把參數一一列出
task testClosure2 <<{
eachMap{
k,v -> println "${k} is ${v}"
}
}
def eachMap(closure){
def map=['w':123,'h':456];
map.each{
closure(it.key,it.value)
}
}
像我們平常要更改生成APP的名稱,在後面添加版本號。會在build.gradle添加如下代碼,現在我們知道執行的是applicationVariants的all方法,後面是一個閉包,閉包裏面有個variant變量,而variant的outputs.add方法也是有一個閉包,執行的就是我們修改輸出app的apk包名
//在apk文件後邊生成版本號信息
applicationVariants.all {
variant ->
variant.outputs.add {
outputFileName = new File(output.outputFile.parent, "app_" + "V" + defaultConfig.versionName + ".apk");
}
}
閉包委託
Groovy閉包的強大之處在於它之處閉包方法的委託,閉包有thisObject,owner,delegate三個屬性,當你再閉包內調用方法時,由它來確定使用哪個對象來處理。默認情況下deletgate和owner是相等的,但是delegate是可以被修改。
示例代碼,定義了一個方法person。設置了委託對象爲當前創建的Person實例,並且設置了委託模式優先,所以,我們在使用person方法創建一個Person的實例時,可以在閉包裏直接對該Person實例配置。
task configClosure <<{
person{
name="張三"
age=18
dumpPerson()
}
}
class Person{
String name
int age
def dumpPerson(){
println "name is ${name},age is ${age}"
}
}
def person(Closure<Person> closure){
Person p=new Person()
closure.delegate=p
//委託模式優先
closure.setResolveStrategy(Closure.DELEGATE_FIRST)
closure(p)
}