作爲一個還處於入門Gradle的小白,記錄一下對Gradle閉包委託的理解。
比如在 《Android Gradle權威指南》 可以看到類似如下代碼段:
static def person(Closure<Person> closure) {
Person p = new Person()
closure.delegate = p
closure.setResolveStrategy(Closure.DELEGATE_FIRST)
closure(p)
}
class Person {
String name
String age
def dumpPerson() {
println "name is ${name},age is ${age}"
}
}
task hello {
person {
name = "momo"
age = "18"
dumpPerson()
}
}
首先person方法中傳進了一閉包Closure<Person>
,Closure是groovy.lang下的一個抽象類,我們指定了範型Person,這裏爲什麼要指定Person呢?
Closure.class
public V call(Object arguments) {
return this.call(new Object[]{arguments});
}
可以調用Closure的call方法來執行閉包,返回值類型即爲指定範型。不過,在as中寫gradle代碼發現並沒有類型強轉的問題(不同類型可以直接賦值),即使不指定範型也不影響執行。不過hello中配置person時會提示Access to 'name' exceeds its access rights
接着看指定代理的代碼:
Person p = new Person()
closure.delegate = p
closure.setResolveStrategy(Closure.DELEGATE_FIRST)
我們創建了一個Person對象,將closure的代理設置爲新創建的Person對象,同時指定處理策略爲代理模式模式優先。
Closure中有三個成員屬性:優先級thisObject>owner>delegate
private Object delegate;
private Object owner;
private Object thisObject;
我們打印一下默認屬性:
static def person(Closure<Person> closure) {
println "closure.thisObject="+closure.thisObject
println "closure.owner="+closure.owner
println "closure.delegate="+closure.delegate
println "closure.resolveStrategy="+closure.resolveStrategy
}
執行./gradlew hello
closure.thisObject=root project 'Study' //上下文
closure.owner=build_3v90txkmyoa0gezpesdi59gev$_run_closure3@294e7e2d
closure.delegate=build_3v90txkmyoa0gezpesdi59gev$_run_closure3@294e7e2d
closure.resolveStrategy=0 // OWNER_FIRST
那我們不設置處理策略可不可以呢?當然是可以的,不設置會優先級順序處理,比如owner沒有相應方法則會交給delegate處理。
接下來調用了closure(p)
,一開始我很不理解,既然已經設置了代理對象,那這段代碼是在幹嘛?其實想複雜了,這就是在調用閉包執行。我們還可以用closure()、closure(null)、closure([1,2,3,4])
等調用,也就是可以不傳參數或傳任意參數。也可以用Closure的call方法調用執行,比如closure.call(p)
因爲我們用的代理模式,我們傳進的參數相當於閉包中的it參數,配置的時候我們並沒有用到。
所以,這裏如果不用代理而用傳參的方式也可以實現類似效果。代碼改動如下:
static def person(Closure<Person> closure) {
Person p = new Person()
closure(p)
}
class Person {
String name
String age
def dumpPerson() {
println "name is ${name},age is ${age}"
}
}
task hello {
person {
it.name = "momo"
it.age = "18"
it.dumpPerson()
}
}