Groovy是一种动态语言,它和Java类似(算是Java的升级版,但是又具备脚本语言的特点),都在Java虚拟机中运行。当运行Groovy脚本时它会先被编译成Java类字节码,然后通过JVM虚拟机执行这个Java字节码类。
Groovy 配置环境变量 在 Groovy 官网下载压缩包 www.groovy-lang.org/download.ht…
然后解压到本地,添加环境变量:环境变量->用户变量->在 Path 环境变量中添加 Groovy 的bin 目录路径
用 CMD 打开命令行,执行:groovy -version , 如果看到版本信息提示,就代表配置成功了。
环境变量配置好之后就可以在命令行执行以下命令运行groovy文件了:groovy MyGroovy.groovy
Groovy console
如果不想进行过多的配置,可以从 android studio 的标题栏进入 Tools/Groovy Console。这里也可以直接运行 groovy 程序。
Android Studio 中运行 groovy 程序
如果想在studio中运行groovy程序,可以参考这篇文章
Groovy语法
学习语法当然是看api最好,官网地址:www.groovy-lang.org/api.html
也有自己的jdk:www.groovy-lang.org/gdk.html
一些常用语法可以参考这篇文章:www.jianshu.com/p/40d7e1768…
变量
Groovy中支持动态类型,即定义变量的时候可以不指定其类型,变量用def关键字声明,也可以直接声明类型:
int a = 10
def b = "groovy"
函数定义时,参数的类型也可以不指定。比如
String testFunction(arg1,arg2){//无需指定参数类型
...
}
除了变量定义可以不指定类型外,Groovy中函数的返回值也可以是无类型的。比如:
//无类型的函数定义,必须使用def关键字
def nonReturnTypeFunc(){
last_line //最后一行代码的执行结果就是本函数的返回值
}
//如果指定了函数返回类型,则可不必加def关键字来定义函数
String getString(){
return"I am a string"
}
字符串
Groovy对字符串支持相当强大,充分吸收了一些脚本语言的优点:
1 单引号''中的内容严格对应Java中的String,不对$符号进行转义
defsingleQuote='I am $ dolloar' //输出就是I am $ dolloar
2 双引号""的内容则和脚本语言的处理有点像,如果字符中有$号的话,则它会$表达式先求值。
def str = "I am one dollar" //输出 I am one dollar
def x = 1
def ss = "I am $x dolloar" //输出I am 1 dolloar
//or
def sss = "I am ${x} dolloar"//输出I am 1 dolloar
3 三个引号'''xxx'''中的字符串支持随意换行,即保留字符串的格式 比如
defmultieLines = ''' begin
line 1
line 2
end '''
l 最后,除了每行代码不用加分号外,Groovy中函数调用的时候还可以不加括号。比如:
println("test") ---> println"test"
字符串的一些用法:
def str = "hello world"
println(str.getAt(1))
println(str[6])
println(str[0..6])//范围
//常用api
each 遍历
find 查询第一个符合条件的值
findAll 找到所有符合条件的值
any 只要有一项符合条件就返回true
every 所有符合条件才返回true
isNumber 是否是数字类型字符串
等等
//结合闭包使用,增加业务逻辑判断
str.find {
String s ->
if (s.isNumber()) {
println(s)
}
}
逻辑控制
if else 和java没区别,switch case更强大,case可以是任意类型的数据
for循环的写法更简洁
def sum = 0
//遍历范围
for (i in 0..10) {
sum += i
}
println(sum)
遍历list
for (i in [0, 1, 2, 3, 4, 5]) {
sum += i
}
println(sum)
遍历map
for (i in ["key1": 1, "key2": 2, "key3": 3]) {
sum += i.value
}
println(sum)
数据结构
- java中的基本数据类型 如int,boolean这些Java中的基本数据类型,在Groovy代码中其实对应的是它们的包装数据类型。
- Groovy中的容器类很简单,就三种:
- List:链表,其底层对应Java中的List接口,一般用ArrayList作为真正的实现类。
- Map:键-值表,其底层对应Java中的LinkedHashMap。
- Range:范围,它其实是List的一种拓展。
List的使用:
变量定义:List变量由[]定义,比如
def aList = [5,'string',true] //List由[]定义,其元素可以是任何对象
变量存取:可以直接通过索引存取,而且不用担心索引越界。如果索引超过当前链表长度,List会自动
往该索引添加元素
assert aList[1] == 'string'
assert aList[5] == null //第6个元素为空
aList[100] = 100 //设置第101个元素的值为10
assert aList[100] == 100
那么,aList到现在为止有多少个元素呢?
println aList.size ===>结果是101
def list = [1, 2, 3, 4, 5]
//list的添加
list.add(6)
println(list.toString())
list << 8
println(list.toString())
//也是添加
def list2 = list + 9
println(list2.toListString())
//删除
list2.removeAll {
return it % 2 == 0
}
println(list2)
//排序
def sortList = [2, 9, 10, 1, 8, 6]
println(sortList.sort())
def sortList2 = ['aaa', 'ss', 'd', 'hhhh']
println sortList2.sort()
//排序,添加排序的条件
println sortList2.sort {
return it.size()
}
//列表的查找
def findList = [2, 5, 8, 13, 22, 67, -9]
println findList.findAll { return it % 2 == 0 }
println findList.any { return it % 2 == 0 }
println findList.every { return it % 2 == 0 }
println findList.min { return Math.abs(it) }
println findList.max()
//统计偶数
println findList.count { return it % 2 == 0 }
Map的使用:
变量定义:Map变量由[:]定义,比如
def aMap = ['key1':'value1','key2':true]
key必须是字符串,value可以是任何对象。另外,key可以用''或""包起来,也可以不用引号包起来。比如
def aNewMap = [key1:"value",key2:true]//其中的key1和key2默认被处理成字符串"key1"和"key2"
Map中元素的存取更加方便,它支持多种方法:
println aMap.keyName <==这种表达方法好像key就是aMap的一个成员变量一样
println aMap['keyName'] <==这种表达方法更传统一点
aMap.anotherkey = "i am map" <==为map添加新元素
def colorMap = [red: 'ff0000', greed: '00ff00', blue: '0000ff']
//get
println colorMap.get('red')
println colorMap['red']
println colorMap.red
//put
colorMap.put('yellow', 'ffff00')
colorMap.yellow = 'ffff00'
//添加不同数据类型的value
colorMap.other = [a: 1, b: 2]
println colorMap.toMapString()
def students = [1: [number: '001', name: 'jack', score: 67],
2: [number: '002', name: 'mike', score: 58],
3: [number: '003', name: 'rose', score: 88]]
//遍历
students.each { def student ->
println "key is ${student.key},value is ${student.value}"
}
students.each {
println "key is ${it.key},value is ${it.value}"
}
//遍历 加入index下标
students.eachWithIndex { def s, int index ->
println "index is ${index},key is ${s.key},value is ${s.value}"
}
//直接遍历key value
students.eachWithIndex { key, value, index ->
println "index is ${index},key is ${key},value is ${value}"
}
//查找
println students.find { def s ->
return s.value.score >= 60
}
//在闭包的条件上再加一个闭包条件 构造查找组合
println students.findAll { def s ->
return s.value.score >= 60
}.collect {
return it.value.name
}
//分组
def group = students.groupBy { def s ->
//"及格" ,"不及格"作为两个新的key
return s.value.score >= 60 ? "及格" : "不及格"
}
println group.toMapString()
//排序 根据成绩排序
println students.sort { def s1, def s2 ->
Number num1 = s1.value.score
Number num2 = s2.value.score
return num1 == num2 ? 0 : num1 > num2 ? 1 : -1
}
Range的使用:
def aRange = 1..5 包含1,2,3,4,5
//如果不想包含最后一个元素,则
def aRangeWithoutEnd = 1..<5
println aRange.from
println aRange.to
//获取
println aRange[0]
//遍历
aRange.each {
return it
}
闭包
闭包,英文叫Closure,是Groovy的核心
//定义
def aClosure = {//闭包是一段代码,所以需要用花括号括起来..
Stringparam1, int param2 -> //这个箭头很关键。箭头前面是参数定义,箭头后面是代码,也可以没用参数
println"this is code" //这是代码,最后一句是返回值,
//也可以使用return,和Groovy中普通函数一样
}
//两种调用方法
aClosure.call()
//or
aClosure()
//无参闭包
def closure = {
println('hello groovy')
}
closure.call()
//有参闭包
def closure2 = { def name ->
println "my name is ${name}"
}
//调用
closure2.call("Rose")
//多个参数
def closure3 = { def name, int age ->
println "my name is ${name},my age is ${age}"
}
closure3.call("mike", 30)
//默认参数
def closure4 = {
println "hello ${it}"
}
closure4.call("world")
//但是,如果在闭包定义时,采用下面这种写法,则表示闭包没有参数!
def noParamClosure = { -> true }
//闭包本身用作业务逻辑的语句块,也可以用作方法的参数,如each方法最后一个参数就算闭包
public static <T> T each(T self, Closure closure)
//原来,Groovy中,当函数的最后一个参数是闭包的话,可以省略圆括号
str.each {
String s ->println(s.isNumber())
}
面向对象
//类
class People {
String name
Integer age
People(String name, Integer age) {
this.name = name
this.age = age
}
def increaseAge(Integer years) {
this.age + years
}
}
//创建实体并赋值
def p = new People("Mike", 50)
println "name is ${p.name},age is ${p.age}"
println p.increaseAge(20)
//接口
interface Action {
void eat()
void drink();
}
//接口实现
class ActionImpl implements Action {
@Override
void eat() {
println("this is eat")
}
@Override
void drink() {
println("this is drink")
}
}
def action = new ActionImpl()
action.eat()
action.drink()
//trait 接口方法有默认实现,类似于接口适配器
trait Action2 {
//不自己实现的要加abstract关键字
abstract void eat()
abstract void drink()
//自己实现的方法
void play() {
println("playing game")
}
}
class Action2Impl implements Action2 {
@Override
void eat() {
println("this is eat2")
}
@Override
void drink() {
println("this is drink2")
}
}
def action2 = new Action2Impl()
action2.eat()
action2.drink()
metaClass为类动态添加属性或者方法
//为类动态添加一个属性
People.metaClass.sex = 'male'
//为类动态添加一个方法
People.metaClass.sexUpperCase = {
-> sex.toUpperCase()
}
//为类动态添加一个静态方法
People.metaClass.static.createPeople = {
String name, int age -> new People(name, age)
}
def p2 = new People("Jack", 42)
println p2.sex
println p2.sexUpperCase()
def p3 = People.createPeople("Rose", 20)
println "this name is ${p3.name},this age is ${p3.age}"
//metaClass使用场景 例如final class 属性和方法的拓展
文件操作
//项目根目录下的文件
def file = new File("./helloGroovy.txt")
//逐行读取
file.eachLine { line ->
println line
}
//一次获取所有文本
def text = file.getText()
def list = file.readLines()
println list.toListString()
//读取文件部分内容
file.withReader { reader ->
char[] buffer = new char[100]
reader.read(buffer)
// println buffer.toString()
return buffer
}
//copy文件
def copy(String sourcePath, String desPth) {
try {
def desFile = new File(desPth)
if (!desFile.exists()) {
desFile.createNewFile()
}
//读取源文件内容
new File(sourcePath).withReader { reader ->
def lines = reader.readLines()
desFile.withWriter { writer ->
lines.each { line ->
// writer.append(line + "\r\n")
writer.writeLine(line)
}
}
}
return true
} catch (Exception e) {
println e.toString()
}
return false
}
copy("E:/learn_demo/GradleDemo/helloGroovy.txt", "E:/learn_demo/GradleDemo/helloCopy.txt")
def copy2(String sourcePath, String desPth) {
try {
def desFile = new File(desPth)
if (!desFile.exists()) {
desFile.createNewFile()
}
def srcFile = new File(sourcePath)
desFile.withOutputStream { out ->
srcFile.withInputStream { inputStream ->
out << inputStream
}
}
} catch (Exception e) {
println e.toString()
}
}
copy2("E:/learn_demo/GradleDemo/helloGroovy.txt", "E:/learn_demo/GradleDemo/helloCopy.txt")
//序列化
def saveObject(Object obj, String desPth) {
try {
def desFile = new File(desPth)
if (!desFile.exists()) {
desFile.createNewFile()
}
desFile.withObjectOutputStream { out ->
out.writeObject(obj)
}
return true
} catch (Exception e) {
println e.toString()
}
return false
}
//反序列化
def readObject(String desPth) {
Object obj = null
try {
def desFile = new File(desPth)
if (desFile == null || !desFile.exists()) {
return false
}
desFile.withObjectInputStream { ins ->
obj = ins.readObject()
}
return true
} catch (Exception e) {
println e.toString()
}
return false
}
XML操作
Groovy中,XML的解析提供了和XPath类似的方法,名为GPath。
test.xml文件:
<response version-api="2.0">
<value>
<books>
<book available="20" id="1">
<title>Don Xijote</title>
<author id="1">Manuel De Cervantes</author>
</book>
<book available="14" id="2">
<title>Catcher in the Rye</title>
<author id="2">JD Salinger</author>
</book>
<book available="13" id="3">
<title>Alice in Wonderland</title>
<author id="3">Lewis Carroll</author>
</book>
<book available="5" id="4">
<title>Don Xijote</title>
<author id="4">Manuel De Cervantes</author>
</book>
</books>
</value>
</response>
GPath的使用:
//第一步,创建XmlSlurper类
def xparser = new XmlSlurper()
def targetFile = new File("test.xml")
//轰轰的GPath出场
GPathResult gpathResult =xparser.parse(targetFile)
//开始玩test.xml。现在我要访问id=4的book元素。
//下面这种搞法,gpathResult代表根元素response。通过e1.e2.e3这种
//格式就能访问到各级子元素....
def book4 = gpathResult.value.books.book[3]
//得到book4的author元素
def author = book4.author
//再来获取元素的属性和textvalue
assert author.text() == ' Manuel De Cervantes '
获取属性更直观
author.@id == '4' 或者 author['@id'] == '4'
属性一般是字符串,可通过toInteger转换成整数
author.@id.toInteger() == 4
好了。GPath就说到这。再看个例子。我在使用Gradle的时候有个需求,就是获取AndroidManifest.xml版本号(versionName)。有了GPath,一行代码搞定,请看:
def androidManifest = newXmlSlurper().parse("AndroidManifest.xml")
println androidManifest['@android:versionName']
或者
println androidManifest.@'android:versionName'
Gradle
Gradl官网地址:docs.gradle.org/current/use…
-
Gradle生命周期
-
Initialization 初始化
Gradle支持单项目和多项目构建。 在初始化阶段,Gradle决定要参与构建的项目,并为每个项目创建一个Project实例。解析settings.gradle文件
-
Configuration 配置
在此阶段,将配置项目对象。 执行作为构建一部分的所有项目的构建脚本。解析所有项目的build.gradle,构建任务的有向图,确定任务的执行顺序。
-
Execution 执行
执行任务
-
-
Gradle的对象 三个对象Gradle Project Settings gradle就是gradle对象。它默认是Settings和Project的成员变量。可直接获取
新建任务可以用project的task()方法,用task方法时,如果没有<<,则闭包在task函数返回前会执行,而如果加了<<,则变成调用myTask.doLast添加一个Action了,自然它会等到grdle myTask的时候才会执行!
-
自定义gradle插件 有三种方式定义gradle插件,具体参考这篇文章:www.jianshu.com/p/265376455…