Gradle 理解 (三):Task

task在gradle占有很重要的地位,因为在gradle中任何执行操作都是通过task来执行。task可以理解成任务,作用就是执行某些指定的操作。

以Android为例,Gradle构建编译一个Android项目的时候,需要执行很多操作流程。整个过程可以通过命令行gradle assembleRelease --info 来看一下:

我们会看到很多task,这些task就是一个一个任务,里面执行特定的操作流程,比如preBuild负责准备配置文件,preReleaseUnitTestBuild负责准备release下的单元测试构建,generateReleaseResources准备资源文件等等,一系列的task执行起来,构建一个完整的apk文件。

一. project

在深入理解task之前,还需要理解另外一个重要而又跟task很大关联的东西:project。

每个可以构建编译的模块就是一个project。还是以Android为例,无论是library,application都是一个project,更简单的理解就是看这个模块是否有build.gradle文件,如果有那么就是一个project。因为project有构建编译等其他的需求,那么自然就需要task,所以project里面包含至少一个task。

为什么说有的build.gradle的模块就是一个project?因为Gradle会默认为每个build.gradle根据配置分配一个project对象,所有我们也能在build.gradle里面默认使用project对象及相对应的API。在build.gradle中,你可以通过API来访问gradle的所有特性,比如task的创建以及依赖管理,在实际开发中,你也会接触到很多API。

下面列出一个project的常用的API图:

1543923049799

这里面的API我们都可以直接在build.gradle里面直接使用,而且不需要实例化project对象,因为每个build.gradle都是分配一个project对象。

通过以上,大概也知道project以及project和task之间的关系了。如果还是不明白,打个比喻:project就是一个公司部门,task就是部分的员工,project的运作只有靠一个个task各司其职才能运作起来。

二. task

2.1 action

上面我们提到task的作用就是执行操作,那么执行操作的动作也就是放置构建逻辑的地方应该如何添加呢?task有个概念-action,就是要执行的动作,内部通过一个集合管理action,task执行的时候像消息队列一样,一个一个action消费执行掉。task提供了doFirst和doLast两个函数来添加action:doFirst ,doLast ,用于添加需要最先执行的Action和需要和需要最后执行的Action。 看个例子:

task helllTask {
    doFirst {
        println "Task doFirst"
    }

    doLast {
        println "Task doLast"

    }
}

我们给helllTask上添加两个action,分别是

{
        println "Task doFirst"
}
{
        println "Task doLast"
}

还是套用之前的部分跟员工的例子,task是一个一个员工的话,那么action就是分配的任务,分别可以选择上班的时候(doFirst)做跟下班的时候做(doLast)。

2.2 依赖

task 有时候需要执行很多很多操作,有些操作跟其他的task是一样的,这时候就可以将这些相同操作的task抽取出来一个基础的task,然后其他的task分别依赖这个基础的task。

task One {
    doFirst {
        println "一言不合先来个1"
    }

}

task Two {
    doFirst {
        println "一言不合先来个2"
    }

}


task Three(dependsOn: [One, Two]) {
    doFirst {
        println "我需要1跟2"
    }
}

终端执行:gradle Three

得到:

> Task :One
一言不合先来个1

> Task :Two
一言不合先来个2

> Task :Three
我需要1跟2

Three依赖了One, Two,在执行的时候先执行One,Two再执行Three。但是注意一个点,不要被dependsOn: [One, Two] 这样的写法迷惑了,不要以为依赖的执行顺序就是从左到右执行,正确的是依赖的执行顺序是不确定。

task One {
    doFirst {
        println "一言不合先来个1"
    }

}

task Two {
    doFirst {
        println "一言不合先来个2"
    }

}

task Four {
    doFirst {
        println "一言不合先来个4"
    }

}


task Three(dependsOn: [One, Two,Four]) {
    doFirst {
        println "我需要1跟2跟4"
    }
}

终端执行:gradle Three

得到:

> Task :Four
一言不合先来个4

> Task :One
一言不合先来个1

> Task :Two
一言不合先来个2

> Task :Three
我需要1跟2跟4

虽然Four是放在最右边的,但是执行却是第一个执行的。为什么task依赖执行是无序呢?因为这些依赖task执行的时候是并行的,这样在编译构建的时候,并行执行能够极大的节约编译执行时间。

这时候你可能会想,如果需要指定一个task一定要执行在另外一个task前面呢,比如先执行单元测试,再执行打包。

这种需求是正常的,gradle肯定也是考虑到的。要实现task顺序,有两种方式:

  • shouldRunAfter/mustRunAfter

taskA.shouldRunAfter(taskB):表示taskB应该在taskA执行后执行。主要这里是should,不是必须要的,也就是还是可能会出现不会按照预设那样执行。

taskA.mustRunAfter(taskB):表示taskB必须在taskA执行后执行。这里是must,一定会按照预设那样执行。

  • finalizedBy

    finalizedBy 也是task的终结器。就是指定一个task在另外一个task结束后必须执行。

    task A {
        doLast {
    
            print "AAAAAA"
        }
    }
    
    task B {
        doLast {
            print "BBBBB"
        }
    }
    
    
    A.finalizedBy B
    

    终端执行:gradle A

    Task :A
    
    AAAAAA
    
    Task :B
    
    BBBBB
    
    

2.3 生命周期

很多框架跟组件都有自己的生命周期,Gradle也有生命周期。Gradle生命周期分为三个部分:初始化阶段,配置阶段,执行阶段。

  • 初始化极端

    在初始化阶段,Gradle为每个build.gradle分配一个project实例对象,初始化阶段相关类似setting.gradle

    的脚本文件 ,然后根据正在执行的项目,找出哪些项目依赖需要参与到构建中来。

  • 配置阶段

    初始化阶段结束后紧跟就是配置阶段。配置阶段的任务是执行各项目下的build.gradle脚本,完成Project的配置,并且构造Task任务依赖关系图以便在执行阶段按照依赖关系执行Task。 Gradle构造了一个模型来表示任务,并且参与到任务构建中来。增量式构建特性决定了模型中的task是否需要被运行。注意,项目中每一次构建的任何配置代码都可以被执行。

  • 执行阶段

    在执行阶段,就是将配置阶段task关系依赖顺序进行执行。因为是增量构建,如果一个task如果被认为没有修改过则不会执行。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值