IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 从Gradle生命周期到自定义Task挂接到Build构建流程全解 -> 正文阅读

[移动开发]从Gradle生命周期到自定义Task挂接到Build构建流程全解

}

void settingsEvaluated(Settings var1) {

println ‘settingsEvaluated()->settings评估完成(settins.gradle中代码执行完毕)’

// var1.gradle.rootProject 这里访问Project对象时会报错,还未完成Project的初始化

}

void projectsLoaded(Gradle var1) {

println ‘projectsLoaded()->项目结构加载完成(初始化阶段结束)’

println ‘projectsLoaded()->初始化结束,可访问根项目:’ + var1.gradle.rootProject

}

void projectsEvaluated(Gradle var1) {

println ‘projectsEvaluated()->所有项目评估完成(配置阶段结束)’

}

void buildFinished(BuildResult var1) {

println 'buildFinished()->构建结束 ’

}

})

在 build.gradle 文件中,也可以拿到 Gradle 对象,但如果在 build.gradle 文件中添加上面的监听事件的话,buildStartedsettingsEvaluatedprojectsLoaded 方法是不会回调的,因为这三个方法是在初始化阶段 执行 settings.gradle 文件的时候执行的,但另外两个方法是会回调的。

在根工程的 build.gradle 文件中,增加如下代码,以便更好的观察上面添加的监听事件的回调时机:

allprojects {

afterEvaluate {

println “${name}:配置完成”

}

}

打印信息如下:

settingsEvaluated()->settings评估完成(settins.gradle中代码执行完毕)

projectsLoaded()->项目结构加载完成(初始化阶段结束)

projectsLoaded()->初始化结束,可访问根项目:root project ‘KotlinLearning’

Configure project :

KotlinLearning:配置完成

Configure project :app

app配置完成

Configure project :kotlinlearning

kotlinlearning配置完成

projectsEvaluated()->所有项目评估完成(配置阶段结束)

buildFinished()->构建结束

2、配置阶段



配置阶段的任务:是执行各项目下的build.gradle脚本,完成 Project 的配置,并且构造Task任务依赖关系图以便在执行阶段按照依赖关系执行Task

2-1、配置阶段执行的代码

配置阶段也是我们最常接触到的构建阶段,比如应用外部构建插件apply plugin: 'com.android.application',配置插件的属性android{ compileSdkVersion 25 ...}等。

每个build.gralde脚本文件对应一个Project对象,在初始化阶段创建,Project接口文档。 配置阶段执行的代码包括:

  • build.gralde中的各种语句

  • 闭包

  • Task中的配置段语句

验证:在根目录的build.gradle中添加如下代码:

println ‘build.gradle的配置阶段’

// 调用Project的dependencies(Closure c)声明项目依赖

dependencies {

// 闭包中执行的代码

println ‘dependencies中执行的代码’

}

// 创建一个Task

task test() {

println ‘Task中的配置代码’

// 定义一个闭包

def a = {

println ‘Task中的配置代码2’

}

// 执行闭包

a()

doFirst {

println ‘这段代码配置阶段不执行’

}

}

println ‘我是顺序执行的’

打印信息如下:

build.gradle的配置阶段

dependencies中执行的代码

Task中的配置代码 Task中的配置代码2 我是顺序执行的

从上面的打印信息可以看出,在执行了dependencies的闭包后,直接执行的是任务test中的配置段代码(Task中除了Action外的代码段都在配置阶段执行)

需要注意的是,执行任何 Gradle 命令,在初始化阶段和配置阶段的代码都会被执行。

2-2、Task 依赖关系配置完成监听

配置阶段另外一个重要的任务就是 构建 Task 依赖关系的有向无环图,说简单一点,就是给 所有的 Task 排一个执行顺序,在执行阶段的时候,就按照这个顺序去执行所有的 Task 任务。

我们可以通过 Gradle 对象的 getTaskGraph 方法来得到该有向无环图对象: TaskExecutionGraph,通过TaskExecutionGraph类的相关方法可以监听 Task 依赖关系构建完成的通知,如:

void whenReady(Closure var1)

void addTaskExecutionGraphListener(TaskExecutionGraphListener var1)

在 build.gradle 文件中,增加如下代码:

gradle.getTaskGraph().whenReady {

println “whenReady Task依赖关系构建完成,size=${it.allTasks.size()}”

it.allTasks.forEach { task ->

println “${task.name}”

}

}

gradle.getTaskGraph().addTaskExecutionGraphListener(new TaskExecutionGraphListener() {

@Override

void graphPopulated(TaskExecutionGraph graph) {

println “graphPopulated Task依赖关系构建完成 size=${graph.allTasks.size()}”

graph.allTasks.forEach { task ->

println “${task.name}”

}

}

})

点击运行按钮,运行app的时候,就可以打印出 Task 任务列表

whenReady Task依赖关系构建完成,size=40 preBuild preDebugBuild compileDebugAidl compileDebugRenderscript generateDebugBuildConfig checkDebugAarMetadata generateDebugResValues generateDebugResources mergeDebugResources createDebugCompatibleScreenManifests extractDeepLinksDebug processDebugMainManifest processDebugManifest processDebugManifestForPackage processDebugResources compileDebugKotlin javaPreCompileDebug compileDebugJavaWithJavac compileDebugSources mergeDebugNativeDebugMetadata mergeDebugShaders compileDebugShaders generateDebugAssets mergeDebugAssets compressDebugAssets processDebugJavaRes mergeDebugJavaResource checkDebugDuplicateClasses dexBuilderDebug desugarDebugFileDependencies mergeExtDexDebug mergeDexDebug mergeDebugJniLibFolders mergeDebugNativeLibs stripDebugDebugSymbols validateSigningDebug writeDebugAppMetadata writeDebugSigningConfigVersions packageDebug assembleDebug graphPopulated Task依赖关系构建完成 size=40 preBuild 。。。。。 assembleDebug

3、执行阶段



执行阶段就是根据配置阶段构建的 Task 依赖关系去执行相关的 Task。

当我们运行项目的时候,Gradle 就会根据 Task的依赖关系依次去执行相关的Task。还可以通过 gradle 命令去执行指定的 Task,如在控制台中输入如下命令,就可以执行 build 任务:

./gradlew build

build 是任务名称。

二、Gradle Hook点

============================================================================


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享

Gradle 提供了非常多的接口回调以便我们修改构建过程中的行为,整体流程如下图所示:

方法说明:

  • Gradle#settingsEvaluated 方法:与BuildListener的settingsEvaluated的执行时机一样,需要在 settings.gradle 文件中添加,否则无效。

  • Gradle#projectsLoaded 方法:与BuildListener的projectsLoaded的执行时机一样,需要在 settings.gradle 文件中添加,否则无效。

  • Gradle#beforeProject方法,在每个工程 配置之前执行,

  • Project#beforeEvaluate方法,在调用该方法的 Project 配置之前执行,如果在 module 的 build.gradle 文件中调用该方法,是不会执行的,因为执行到build.gradle的时候,已经过了beforeEvaluate执行的时间节点了。

  • Gradle#afterProject方法,在每个工程配置完成之后,执行该方法,哪怕构造过程出错,也会调用,截止到出错的文件。

  • Project#afterEvaluate方法,在调用该方法的Project 配置执行完成之后调用,在这个时机,该工程就配置完成了,如在这个方法回调中就可以获取到所有的Task任务了。

  • Gradle#projectsEvaluate方法,当所有的工程都配置完成之后,执行该方法,与BuildListener的projectsEvaluated方法的执行时机是一样的。

三、指定 Task 执行顺序

============================================================================


在Gradle中,有三种方式指定task的执行顺序:

  • dependsOn 强依赖方式

  • 通过Task输入输出

  • 通过API指定执行顺序

3-1、通过dependsOn强依赖方式指定


dependsOn 强依赖的方式可以细分为 静态依赖动态依赖

  • 静态指定依赖:在创建task的时候,就明确的知道定义的 Task需要依赖的task是什么,直接通过 dependsOn 参数或者 dependsOn 方法指定所依赖的Task。

task提供了dependsOn,finalizedBy方法来管理task之间的依赖关系,依赖关系表达的是执行这个task时所需要依赖的其他task,也就是说这个task不能被单独执行,执行这个 Task 之前或之后需要执行另外的task。

  • 动态指定依赖:在创建 Task的时候,不知道需要依赖哪些 Task,通过 dependsOn 方法动态依赖符合条件的 Task

示例代码如下所示:

静态指定依赖

在定义 Task 的时候,直接为 Task 指定 dependsOn 参数,值为 另一个被依赖的 Task 的名字:

task taskX {

doLast{

println ‘taskX’

}

}

task taskY {

doLast{

println ‘taskY’

}

}

task taskZ(dependsOn:taskX) { // 多依赖方式:dependsOn:[taskX,taskY]

doLast{

println ‘taskZ’

}

}

// 当我们执行taskZ的时候,由于依赖了taskX,则taskX会先执行,然后才会执行:taskZ

除了在 Task 定义的时候指定 Task 的依赖之外,还可以通过 TaskdependsOn 方法,为 Task 指定依赖:

task taskZ {// 定义Task的时候不指定依赖

doLast{

println ‘taskZ’

}

}

// 通过task的dependsOn方法,也可以指定task的依赖task。

taskZ.dependsOn(taskX,taskY)

当一个task依赖多个task的时候,被依赖的task之间,如果没有依赖关系的话,那么他们的执行顺序是随机的,并无影响。

动态添加依赖

当 Task 在定义的时候,不知道所依赖的 Task 是什么,在配置阶段,通过条件找出符合条件的 Task ,并进行依赖。

task lib1 {

doLask{

println ‘lib1’

}

}

task lib2 {

doLask{

println ‘lib2’

}

}

task lib3 {

doLask{

println ‘lib3’

}

}

// 动态指定taskX依赖所有以lib开头的task

task taskX{

// 动态指定依赖

dependsOn this.tasks.findAll{ task->

return task.name.startsWidth(‘lib’)

}

doLast {

println ‘taskZ’

}

}

3-2、通过Task输入输出指定


当一个参数作为TaskA的输出参数,同时又作为TaskB的输入参数。那么当执行TaskB的时候先要执行TaskA。即输出的Task先于输入的Task执行。 如:

ext {

testFile = file("${this.buildDir}/test.txt")

}

// 生产者 Task

task producer {

outputs.file testFile

doLast {

outputs.getFiles().singleFile.withWriter { writer ->

writer.append(“我爱中国”)

}

println “producer Task 执行结束”

}

}

// 消费者 Task

task consumer {

inputs.file testFile

doLast {

println “读取文件内容:${inputs.files.singleFile.text}”

println “consumer Task 执行结束”

}

}

task testTask(dependsOn: [producer, consumer]) {

doLast {

println “测试Task执行结束”

}

}

文件 testFile 是 producer 的输出参数,是 consumer 的输入参数,所以 producer 优先于 consumer 执行。

3-3、通过API指定执行顺序


可以指定Task执行顺序的方法还有:

  • mustRunAfter:指定必须在哪个Task执行完成之后在执行,如 taskA.mustRunAfter(taskB),表示 taskA 必须在 taskB 之后执行。

  • shouldRunAfter:跟mustRunAfter类似,区别在于不强制。不常用。

  • finalizedBy :在任务结束之后执行指定的 Task。如:taskA.finalizedBy(taskB),表示在 taskA 执行完成之后,再执行 taskB 任务。

示例代码:

  • 通过mustRunAfter 指定task执行顺序:

task taskA {

doLast {

println “taskA 执行”

}

}

task taskB {

mustRunAfter(taskA)

doLast {

println “taskB 执行”

}

}

task testAB(dependsOn: [taskA, taskB]) {

doLast {

println “testAB 执行”

}

}

执行 任务:testAB,输出信息为:

? shouldRunAfter与mustRunAfter类似,这就不在测试了。

  • 通过 finalizedBy 指定 Task 的执行顺序

task taskA {

doLast {

println “taskA 执行”

}

}

task taskB {

finalizedBy(taskA)

doLast {

println “taskB 执行”

}

}

task testAB(dependsOn: [taskA, taskB]) {

doLast {

println “testAB 执行”

}

}

同样的代码,就把 mustRunAfter 替换成了 finalizedBy 方法,按照finalizedBy 方法的含义,就是:taskB 执行结束后,再执行 taskA。运行 testAB 任务,输出信息为:

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-12-14 16:03:59  更:2021-12-14 16:07:02 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 9:42:28-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码