编写 Gradle 任务Task

前面几节课我们先介绍了 Gradle,然后学习了 Groovy 的基础语法,紧接着介绍了 Android 项目中 Gradle 的配置。我们从配置中可以看出 Gradle 的构建都是基于任务(Task) 的,有了前面几节的基础,今天这节课我们来学习一下,怎么样去定义一个 Gradle 的任务(Task) ,以及Task的生命周期。

1. 声明 Task

关于 Task 的声明,我们其实在第三节《构建自己的 Gradle 工程》这一节里面就有所介绍,我们创建 Gradle 项目时就声明了一个 Task 为 hello,下面我们声明一个名字为 mTask 的 Task。

task mTask{
     doLast{
       println "Hello,这是我声明的Task"
     }
}

我们在控制台执行命令gradle mTask,我们会看到输出结果。

$ gradle mTask
Starting a Gradle Daemon (subsequent builds will be faster)

> Task :mTask
Hello,这是我声明的Task

BUILD SUCCESSFUL in 13s
1 actionable task: 1 executed

一般情况下,我们这样声明 Task,其实创建的都是org.gradle.api.DefaultTask的对象,它是org.gradle.api.Task的一个实现。DefaultTask的所有属性都是私有的,只能通过 get 和 set 方法获取。

Tips: 其实 Task 的声明除了上面方法外还有下面 2 种方法:

//Task的第二种声明方法
task (mTask){
     doLast{
       println "Hello,这是我声明的Task"
     }
}
//Task的第三种声明方法
task ('mTask'){
     doLast{
       println "Hello,这是我声明的Task"
     }
}

2. 给 Task 添加 Action

我们创建一个 Task 后可以根据我们的需要给 Task 添加不同的 Action,上面的“doLast”就是给队列尾增加一个Action。下面我们先来了解以下,关于 Task 添加 Action 的一些 API

 //在Action 队列头部添加Action
 Task doFirst(Action<? super Task> action);
 Task doFirst(Closure action);

 //在Action 队列尾部添加Action
 Task doLast(Action<? super Task> action);
 Task doLast(Closure action);
    
 //已经过时了,建议用 doLast 代替
 Task leftShift(Closure action);

 //删除所有的Action
 Task deleteAllActions();

关于上面的 API,deleteAll 就是删除所有的 Action,这个我们不用太多讲解,而 leftShiftdoLast 其实是一样的就是在队列的尾部增加一个 Action。这个 leftShift API 已经过时,我们建议使用 doLast 代替。关于 doFirstdoLast 我们下面通过一个例子来讲解:

//创建一个名字为apiTask的 task 
task apiTask {

    //创建一个 Action , 添加到 Action 列表的头部
   doFirst(new Action<Task>() {
       @Override
       void execute(Task task) {
           println "action1++++++++++"
       }
   })

    //创建一个 Action , 添加到 Action 列表的头部
    doFirst {
        println "action2++++++++++"
    }

	//创建一个 Action , 添加到 Action 列表的尾部
    doLast(new Action<Task>() {
       @Override
       void execute(Task task) {
           println "action3++++++++++"
       }
   })
    	//创建一个 Action , 添加到 Action 列表的尾部
	doLast {
        println "action4++++++++++"
    }
}

我们在上面的例子的 Task 队列中,先添加了 action1,然后再在头部添加了 action2,现在队列从头到尾应该是"action2=>action1"然后再在队尾增加 action3,action4,最终队列里面从头至尾依次为:“action2 => action1 => action3 => action4”。我们下面执行 apiTask 任务看看是不是输出这个顺序。

图片描述

3. 定义 Task 的依赖

关于 Task,它也是可以进行依赖的,Task 声明依赖的关键字是dependsOn,它支持声明一个或多个依赖,下面我们看个例子:

task first {
	doLast {
        println "+++++first+++++"
    }
}
task second {
	doLast {
        println "+++++second+++++"
    }
}

//指定多个task依赖
task print(dependsOn :[second,first]) {
	doLast {
      logger.quiet "指定多个task依赖"
    }
}

task third(dependsOn : print) {
	doLast {
      println '+++++third+++++'
    }
}

// //还可以采用这样的方式
// task third {
// 	doLast {
//         println "+++++third+++++"
//     }
// }
// third.dependsOn('print')

我们分别执行gradle printgradle third命令:

图片描述

图片描述
我们从上面的执行结果中可以看出,执行 Task 之前,会先执行它的依赖 Task。

4. Task 的执行顺序

我们通过前面dependsOn关键字的定义知道,如果一个 Task 定义了依赖,那么执行这个 Task 之前,它的依赖 Task 需要先执行。这也就是 Gradle 的一个比较优秀思想:声明在一个给定的 Task 执行之前什么 Task 该被执行,而没有定义如何去执行。 在 Gradle 中 Task 的执行顺序是由输入/输出规范自动确定的。既然这么做,肯定是有优点的,那么我们看下它的优点:

优点:

  1. 由于没有明确规定,如何去执行,而是规定什么先去执行,这就是支持 Task 并行。这样可以极大的节约构建的时间成本。
  2. 我们只需要关注依赖任务,不用去关注依赖链上的关系是否发生变化。

5. Gradle 构建的生命周期

前面我们说了 Task 的执行顺序,下面我们了解以下 Gradle 构建的生命周期。我们学习 Android 时候我们知道,一个应用(Application)、活动(Activity)、服务(Service)都是有生命周期。同样今天我们学习的 Gradle 的构建它也是有生命周期的。Gradle 构建的生命周期有三个阶段:初始阶段,配置阶段运行阶段

5.1 初始阶段

在这个阶段,Gradle 项目根据正在执行的项目,找出哪些项目依赖需要参与到构建中。在 Android 项目中就是根据setting.gradleinclude信息,查看有模块项目参与到构建中。

Tips: 在这个构建阶段当前已有的构建脚本代码都不会被执行。

5.2 配置阶段

在这个阶段,Gradle 创建了一个模型来代表任务,并参与到项目构建中来。Android 项目中这个阶段就是执行build.gradle 脚本文件。

5.3 运行阶段

这个阶段,就是根据 Gradle 命令传递过来的 Task 的名称,执行相关的依赖任务。Task 的 Action 会在这个阶段执行。

下面分享一个小技巧。

Tips: 自定义 Task 的名字最好采用驼峰命名法

我们以我们上面的 apiTask 来定义:

//创建一个名字为apiTask的 task 
task apiTask {

    //创建一个 Action , 添加到 Action 列表的头部
   doFirst(new Action<Task>() {
       @Override
       void execute(Task task) {
           println "action1++++++++++"
       }
   })

    //创建一个 Action , 添加到 Action 列表的头部
    doFirst {
        println "action2++++++++++"
    }

	//创建一个 Action , 添加到 Action 列表的尾部
    doLast(new Action<Task>() {
       @Override
       void execute(Task task) {
           println "action3++++++++++"
       }
   })
    	//创建一个 Action , 添加到 Action 列表的尾部
	doLast {
        println "action4++++++++++"
    }
}

前面我们执行命令是:gradle apiTask,我们使用来驼峰命名法还可以使用gradle aT来执行。

图片描述

这个我们其实日常开发中也遇到过,我们打包时执行的gradle aR 相当于gradlew assembleRelease

6. 小结

这篇文章我们从 Task 的声明开始,介绍了如何声明 Task,再到给 Task 添加 Action,逐步深入,再介绍了 Task 的依赖,执行顺序,以及 Gradle 构建的生命周期。通过这一篇文章,大家应该对 Task 有了一定的认识和理解。这将为我们后面组件化和插件化打下基础。