Android方向的第一期文章,会专注于Gradle系列,名字叫做『Gradle从入门到实战』,计划有如下几个课程:
Groovy基础全面理解Gradle如何创建Gradle插件分析Android的buildtools插件实战,从0到1完成一款Gradle插件本篇文章讲解Groovy基础。为什么是Groovy基础呢,因为玩转Gradle并不需要学习Groovy的全部细节。Groovy是一门jvm语言,功能比较强大,细节也很多,全部学习的话比较耗时,对我们来说收益较小。
为什么是Gradle?Gradle是目前Android主流的构建工具,不管你是通过命令行还是通过AndroidStudio来build,最终都是通过Gradle来实现的。所以学习Gradle非常重要。
目前国内对Android领域的探索已经越来越深,不少技术领域如插件化、热修复、构建系统等都对Gradle有迫切的需求,不懂Gradle将无法完成上述事情。所以Gradle必须要学习。
如何学习Gradle?大部分人对Gradle表示一脸懵逼,每当遇到一个问题的时候都需要从网上去查,这是一个误区。
Gradle不单单是一个配置脚本,它的背后是几门语言,如果硬让我说,我认为是三门语言。
GroovyLanguageGradleDSLAndroidDSLDSL的全称是DomainSpecificLanguage,即领域特定语言,或者直接翻译成“特定领域的语言”,算了,再直接点,其实就是这个语言不通用,只能用于特定的某个领域,俗称“小语言”。因此DSL也是语言。
在你不懂这三门语言的情况下,你很难达到精通Gradle的程度。这个时候从网上搜索,或者自己记忆的一些配置,其实对你来说是很大的负担。但是把它们当做语言来学习,则不需要记忆这些配置,因为语言都是有文档的,我们只需要学语法然后查文档即可,没错,这就是学习方法,这就是正道。
你需要做什么呢?跟着我学习就行啦!下面步入正题,让我们来开始学习Groovy的基本语法。
Groovy和Java的关系Groovy是一门jvm语言,它最终是要编译成class文件然后在jvm上执行,所以Java语言的特性Groovy都支持,我们完全可以混写Java和Groovy。
既然如此,那Groovy的优势是什么呢?简单来说,Groovy提供了更加灵活简单的语法,大量的语法糖以及闭包特性可以让你用更少的代码来实现和Java同样的功能。比如解析xml文件,Groovy就非常方便,只需要几行代码就能搞定,而如果用Java则需要几十行代码。
Groovy的变量和方法声明在Groovy中,通过def关键字来声明变量和方法,比如:
defa=1;
defb="helloworld";
defintc=1;
defhello(){
println("helloworld");
return1;
}
在Groovy中,很多东西都是可以省略的,比如
语句后面的分号是可以省略的变量的类型和方法的返回值也是可以省略的方法调用时,括号也是可以省略的甚至语句中的return都是可以省略的所以上面的代码也可以写成如下形式:
defa=1
defb="helloworld"
defintc=1
defhello(){
println"helloworld"//方法调用省略括号
1;//方法返回值省略return
}
defhello(Stringmsg){
println(msg)
}
//方法省略参数类型
inthello(msg){
println(msg)
return1
}
//方法省略参数类型
inthello(msg){
printlnmsg
return1//这个return不能省略
println"done"
}
总结
在Groovy中,类型是弱化的,所有的类型都可以动态推断,但是Groovy仍然是强类型的语言,类型不匹配仍然会报错;在Groovy中很多东西都可以省略,所以寻找一种自己喜欢的写法;Groovy中的注释和Java中相同。Groovy的数据类型在Groovy中,数据类型有:
Java中的基本数据类型Java中的对象Closure(闭包)加强的List、Map等集合类型加强的File、Stream等IO类型类型可以显示声明,也可以用def来声明,用def声明的类型Groovy将会进行类型推断。
基本数据类型和对象这里不再多说,和Java中的一致,只不过在Gradle中,对象默认的修饰符为public。下面主要说下String、闭包、集合和IO等。
1.String
String的特色在于字符串的拼接,比如
defa=1
defb="hello"
defc="a=${a},b=${b}"
printlnc
outputs:
a=1,b=hello
2.闭包
Groovy中有一种特殊的类型,叫做Closure,翻译过来就是闭包,这是一种类似于C语言中函数指针的东西。闭包用起来非常方便,在Groovy中,闭包作为一种特殊的数据类型而存在,闭包可以作为方法的参数和返回值,也可以作为一个变量而存在。
如何声明闭包?
{parameters->
code
}
闭包可以有返回值和参数,当然也可以没有。下面是几个具体的例子:
defclosure={inta,Stringb->
println"a=${a},b=${b},Iamaclosure!"
}
//这里省略了闭包的参数类型
deftest={a,b->
println"a=${a},b=${b},Iamaclosure!"
}
defryg={a,b->
a+b
}
closure(100,"renyugang")
test.call(100,200)
defc=ryg(100,200)
printlnc
闭包可以当做函数一样使用,在上面的例子中,将会得到如下输出:
a=100,b=renyugang,Iamaclosure!
a=100,b=200,Iamaclosure!
300
另外,如果闭包不指定参数,那么它会有一个隐含的参数it
//这里省略了闭包的参数类型
deftest={
println"find${it},Iamaclosure!"
}
test(100)
outputs:
find100,Iamaclosure!
闭包的一个难题是如何确定闭包的参数,尤其当我们调用Groovy的API时,这个时候没有其他办法,只有查询Groovy的文档:
http://www.groovy-lang.org/api.html
http://docs.groovy-lang.org/latest/html/groovy-jdk/index-all.html
下面会结合具体的例子来说明如何查文档。
3.List和Map
Groovy加强了Java中的集合类,比如List、Map、Set等。
List的使用如下:
defemptyList=[]
deftest=[100,"hello",true]
test[1]="world"
printlntest[0]
printlntest[1]
test<<200
printlntest.size
outputs:
100
world
4
List还有一种看起来很奇怪的操作符<<,其实这并没有什么大不了,左移位表示向List中添加新元素的意思,这一点从文档当也能查到。
其实Map也有左移操作,这如果不查文档,将会非常费解。
Map的使用如下:
defemptyMap=[:]
deftest=["id":1,"name":"renyugang","isMale":true]
test["id"]=2
test.id=900
printlntest.id
printlntest.isMale
outputs:
900
true
可以看到,通过Groovy来操作List和Map显然比Java简单的多。
这里借助Map再讲述下如何确定闭包的参数。比如我们想遍历一个Map,我们想采用Groovy的方式,通过查看文档,发现它有如下两个方法,看起来和遍历有关:
可以发现,这两个each方法的参数都是一个闭包,那么我们如何知道闭包的参数呢?当然不能靠猜,还是要查文档。
通过文档可以发现,这个闭包的参数还是不确定的,如果我们传递的闭包是一个参数,那么它就把entry作为参数;如果我们传递的闭包是2个参数,那么它就把key和value作为参数。
按照这种提示,我们来尝试遍历下:
defemptyMap=[:]
deftest=["id":1,"name":"renyugang","isMale":true]
test.each{key,value->
println"twoparameters,find[${key}:${value}]"
}
test.each{
println"oneparameters,find[${it.key}:${it.value}]"
}
outputs:
twoparameters,find[id:1]
twoparameters,find[name:renyugang]
twoparameters,find[isMale:true]
oneparameters,find[id:1]
oneparameters,find[name:renyugang]
oneparameters,find[isMale:true]
另外一个eachWithIndex方法教给大家练习,自己查文档,然后尝试用这个方法去遍历。
试想一下,如果你不知道查文档,你又怎么知道each方法如何使用呢?光靠从网上搜,API文档中那么多接口,搜的过来吗?记得住吗?
4.加强的IO
在Groovy中,文件访问要比Java简单的多,不管是普通文件还是xml文件。怎么使用呢?还是来查文档。
根据File的eachLine方法,我们可以写出如下遍历代码,可以看到,eachLine方法也是支持1个或2个参数的,这两个参数分别是什么意思,就需要我们学会读文档了,一味地从网上搜例子,多累啊,而且很难彻底掌握:
deffile=newFile("a.txt")
println"readfileusingtwoparameters"
file.eachLine{line,lineNo->
println"${lineNo}${line}"
}
println"readfileusingoneparameters"
file.eachLine{line->
println"${line}"
}
outputs:
readfileusingtwoparameters
1欢迎
2关注
3玉刚说
readfileusingoneparameters
欢迎
关注
玉刚说
除了eachLine,File还提供了很多Java所没有的方法,大家需要浏览下大概有哪些方法,然后需要用的时候再去查就行了,这就是学习Groovy的正道。
下面我们再来看看访问xml文件,也是比Java中简单多了。
Groovy访问xml有两个类:XmlParser和XmlSlurper,二者几乎一样,在性能上有细微的差别,如果大家感兴趣可以从文档上去了解细节,不过这对于本文不重要。
在下面的链接中找到XmlParser的API文档,参照例子即可编程,
http://docs.groovy-lang.org/docs/latest/html/api/。
假设我们有一个xml,attrs.xml,如下所示:
<resources>
<declare-styleablename="CircleView">
<attrname="circle_color"format="color">#98ff02</attr>
<attrname="circle_size"format="integer">100</attr>
<attrname="circle_title"format="string">renyugang</attr>
</declare-styleable>
</resources>
那么如何遍历它呢?
defxml=newXmlParser().parse(newFile("attrs.xml"))
//访问declare-styleable节点的name属性
printlnxml['declare-styleable'].@name[0]
//访问declare-styleable的第三个子节点的内容
printlnxml['declare-styleable'].attr[2].text()
outputs:
CircleView
renyugang
更多的细节都可以从我发的那个链接中查到,大家有需要查文档即可。
Groovy的其他特性
除了本文中已经分析的特性外,Groovy还有其他特性。
Class是一等公民在Groovy中,所有的Class类型,都可以省略.class,比如:
func(File.class)
func(File)
deffunc(Classclazz){
}
Getter和Setter在Groovy中,Getter/Setter和属性是默认关联的,比如:
classBook{
privateStringname
StringgetName(){returnname}
voidsetName(Stringname){this.name=name}
}
classBook{
Stringname
}
上述两个类完全一致,只有有属性就有Getter/Setter;同理,只要有Getter/Setter,那么它就有隐含属性。
with操作符在Groovy中,当对同一个对象进行操作时,可以使用with,比如:
Bookbk=newBook()
bk.id=1
bk.name="androidart"
bk.press="chinapress"
可以简写为:
Bookbk=newBook()
bk.with{
id=1
name="androidart"
press="chinapress"
}
判断是否为真在Groovy中,判断是否为真可以更简洁:
if(name!=null&&name.length>0){}
可以替换为:
if(name){}
简洁的三元表达式在Groovy中,三元表达式可以更加简洁,比如:
defresult=name!=null?name:"Unknown"
//省略了name
defresult=name?:"Unknown"
简洁的非空判断在Groovy中,非空判断可以用?表达式,比如:
if(order!=null){
if(order.getCustomer()!=null){
if(order.getCustomer().getAddress()!=null){
System.out.println(order.getCustomer().getAddress());
}
}
}
可以简写为:
printlnorder?.customer?.address
使用断言在Groovy中,可以使用assert来设置断言,当断言的条件为false时,程序将会抛出异常:
defcheck(Stringname){
//namenon-nullandnon-emptyaccordingtoGroovyTruth
assertname
//safenavigation+GroovyTruthtocheck
assertname?.size()>3
}
switch方法在Groovy中,switch方法变得更加灵活,可以同时支持更多的参数类型:
defx=1.23
defresult=""
switch(x){
case"foo":result="foundfoo"
//letsfallthrough
case"bar":result+="bar"
case[4,5,6,'inList']:result="list"
break
case12..30:result="range"
break
caseInteger:result="integer"
break
caseNumber:result="number"
break
case{it>3}:result="number>3"
break
default:result="default"
}
assertresult=="number"
==和equals在Groovy中,==相当于Java的equals,,如果需要比较对个对象是否是同一个,需要使用.is()。
Objecta=newObject()
Objectb=a.clone()
asserta==b
assert!a.is(b)
本小节参考了如下文章,十分感谢原作者的付出:
1.http://www.jianshu.com/p/ba55dc163dfd
编译、运行Groovy可以安装Groovysdk来编译和运行。但是我并不想搞那么麻烦,毕竟我们的最终目的只是学习Gradle。
推荐大家通过这种方式来编译和运行Groovy。
在当面目录下创建build.gradle文件,在里面创建一个task,然后在task中编写Groovy代码即可,如下所示:
task(yugangshuo).doLast{
println"startexecuteyuangshuo"
haveFun()
}
defhaveFun(){
println"havefun!"
System.out.println("havefun!");
1
deffile1=newFile("a.txt")
deffile2=newFile("a.txt")
assertfile1==file2
assert!file1.is(file2)
}
classBook{
privateStringname
StringgetName(){returnname}
voidsetName(Stringname){this.name=name}
}
只需要在haveFun方法中编写Groovy代码即可,如下命令即可运行:
gradleyugangshuo
artgroovy
前言Android方向的第一期文章,会专注于Gradle系列,名字叫做『Gradle从入门到实战』,计划有如下几个课程:Groovy基础全面理解Gradle如何创建Gradle插件分析Android的bu(98)人阅读时间:2024-03-06 05:42:028877b
出门前尤其是坐飞机前一定要看黄历,否则没准就会经历惊魂一刻。中国南方航空木棉花标志1999年6月9日下午17时06分,距离广东湛江机场18.5公里处,一架隶属于中国南方航(57)人阅读时间:2024-03-06 05:42:029788小游戏
推荐一个非常简单的益智游戏:晚上睡觉前和孩子躺在被窝里,关上灯,用手指在孩子的手心里慢慢的写一些笔画不是太复杂的字,然后让孩子猜猜写的是什么字。也可以反过来让(75)人阅读时间:2024-03-06 05:42:02appsync怎么安装
iOS14.4Beta越狱成功..Jailbreak#checkra1n#iOS14.4Beta1+checkra1n经证实-@___t0mi___,它仅在A9设备和Iphonex之前有效,但没有人脸ID...。在A10和A10X设备上不起作(58)人阅读时间:2024-03-06 05:42:02