gradle笔记

123 阅读5分钟

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)

数据结构

  1. java中的基本数据类型 如int,boolean这些Java中的基本数据类型,在Groovy代码中其实对应的是它们的包装数据类型。
  2. 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…

  1. Gradle生命周期

    • Initialization 初始化

      Gradle支持单项目和多项目构建。 在初始化阶段,Gradle决定要参与构建的项目,并为每个项目创建一个Project实例。解析settings.gradle文件

    • Configuration 配置

      在此阶段,将配置项目对象。 执行作为构建一部分的所有项目的构建脚本。解析所有项目的build.gradle,构建任务的有向图,确定任务的执行顺序。

    • Execution 执行

      执行任务

  2. Gradle的对象 三个对象Gradle Project Settings gradle就是gradle对象。它默认是Settings和Project的成员变量。可直接获取

    新建任务可以用project的task()方法,用task方法时,如果没有<<,则闭包在task函数返回前会执行,而如果加了<<,则变成调用myTask.doLast添加一个Action了,自然它会等到grdle myTask的时候才会执行!

  3. 自定义gradle插件 有三种方式定义gradle插件,具体参考这篇文章:www.jianshu.com/p/265376455…