gradle 执行过程
1.初始化阶段 2.配置阶段 3.执行阶段
初始化阶段 其实对应的就是我们的settings.gradle 文件。 配置阶段 就是主要目的就是为了构建出我们的 task和task之间的依赖关系 也就是谁先执行 谁后执行的 有向无环图。 执行阶段 就是整个gradle 最终 build 你project的 阶段了
task 定义以及配置
task的定义其实比较重要的就是group属性了,很多人都忽略了这个属性,导致定义的task 全都在默认的other分组中,找起来很难找。
也可以看看 task 总共有哪些属性可以设置
这里要注意了,task里面代码的执行时机,比如说
//默认是在other分组 大部分的blog就只写了这种方式
task helloTask {
println 'helloTask1 '
doFirst {
println("helloTask2")
}
}
看下执行结果
也就是说你在task里面 直接写的语句 他是在 config阶段去执行的。 只有写在dofirst 或者dolast 必包里面的 才是最终在gradle执行阶段执行的
统计assembleDefaultDebug 时长
有了上述的基础,我们来做个简单的小功能,统计一下 build 这个task 的耗时。 要统计他的耗时 我们肯定要知道这个assembleDefaultDebug task是从哪里开始的。这个我们只要输入一下这个build的命令 然后查看一下 从哪个task开始的即可
从上图可得知 这是从preBuild 这个task开始的。
this.afterEvaluate { Project project ->
def preTask = project.tasks.getByName('preBuild')
def t1
preTask.doFirst {
t1 = System.currentTimeMillis()
}
def buildTask = project.tasks.getByName('assembleDefaultDebug')
buildTask.doLast {
println("build takes:" + (System.currentTimeMillis() - t1))
}
}
看下执行结果
task 依赖
网上一些随处可见的 依赖相关知识 我就不多重复了,我讲点 别人没提到的。
首先 一个task 是可以依赖 多个task的。 并不是说一个task 只能depends 一个task
task taskX{
doLast {
println "taskX"
}
}
task taskY{
doLast {
println "taskY"
}
}
task taskZ(dependsOn:[taskX,"assembleDebug"]){
doLast {
println "taskZ"
}
}
此外,上述的例子中 taskZ依赖于 task X和task Y,千万不要以为我把task X 写在taskY的前面 就代表 x先于y的执行。 网上有很多人说 这里taskX和taskY的执行顺序是 随机的,但是从我自己多次测试的结果来看,似乎并不是这样,而是根据taskX和taskY的 名称来的,从第一个字母开始 字母越大的执行的时候 就在前面。 可能因为我gradle版本过高的缘故?反正这里大家要小心一点,可以多做做测试,留言板上与我交流
另外task还可以动态依赖。 比如说你可以依赖某些 符合某些规则的task。
task taskZ{
// 通过程序的输出来指定依赖
dependsOn this.tasks.findAll { task ->
return task.name.startsWith("build")
}
doLast {
println "taskZ"
}
}
task 输入输出
我们首先看一下 程序的输出
可以看出来 只支持 文件或者文件路径的输出。
再看下输入,这里也很明显了, 除了支持文件和文件路径的输入以外 还支持map类型的输入,注意这个map的value 是object 也就是说 可以支持任何类型。
做一个小功能,我们把我们android minSdk和versionSdk 等等 输出到一个文件里。
ext {
mMinSdkVersion = 26
mTargetSdkVersion = 29
infoFile = file(this.projectDir.toString() + "/info.txt")
if (!infoFile.exists()) {
infoFile.createNewFile()
}
}
先定义 version然后定义 输出的文件。
看下写文件任务
task writeInfoTask() {
inputs.property("mMinSdkVersion", this.mMinSdkVersion.toString())
inputs.property("mTargetSdkVersion", this.mTargetSdkVersion.toString())
outputs.files this.infoFile
doLast {
println("writeInfoTask")
def data = inputs.getProperties()
File file = outputs.getFiles().getSingleFile()
file.write(data.toString())
}
}
task zreadInfoTask() {
inputs.files this.infoFile
doLast {
println("readInfoTask")
File file = inputs.getFiles().getSingleFile()
println("file content:" + file.text)
}
}
最后我们来执行一下这个任务
task taskX {
dependsOn(writeInfoTask, zreadInfoTask)
doLast {
println("task all over")
}
}
注意看我这里为啥不叫readInfoTask而是叫zredInfoTask? 因为网上有很多人说 gradle可以智能判定,当一个task的输入依赖一个文件,而这个文件又是另外一个task的输出的时候,gradle可以智能的将 输出文件的task放在前面, 输入文件的task放在后面。 但是我这里测试的结果来看,并不是这样。 大家可以自行试试,看看是不是和gradle的版本有关 导致这个特性不同。
此外还有一个mustRunAfter函数 也可以保证在某个任务执行完毕以后执行。有兴趣的可以自行探索一番。