Android Gradle学习系列(七)-Gradle核心之Task详解与实战

前言

这一篇我们来说说Gradle中另外一个重要的概念Task

1.Task的定义和配置

1.1Task的定义

第一种:可以直接通过task函数去定义

在这里插入图片描述

在这里插入图片描述

第二种:通过TaskContainer
在这里插入图片描述
就是我们上面用红框圈起来的那个,那怎么创建呢?直接调用create方法即可
在这里插入图片描述

在这里插入图片描述
这两种方式有啥区别呢?实际上第一种方式最终也是会添加到TaskContainer中,TaskContainer相当于我们Task的管理类,既然是管理类,那么就不止可以创建,我们看下它的源码

@HasInternalProtocol
public interface TaskContainer extends TaskCollection<Task>, PolymorphicDomainObjectContainer<Task> {
	...
    @Nullable
    Task findByPath(String path);

    Task getByPath(String path) throws UnknownTaskException;

    <T extends Task> T create(String name, Class<T> type, Action<? super T> configuration) throws InvalidUserDataException;

    TaskProvider<Task> register(String name, Action<? super Task> configurationAction) throws InvalidUserDataException;

    Task replace(String name);
    ...

我们看完源码发现TaskContainer主要就是查找和新增,其他我们几乎很少使用

1.2 Task的配置

比如我们想为我们的task配置组名和描述

第一种:我们在定义的时候直接对它进行配置
在这里插入图片描述
第二种:在配置代码块中调用各种配置方法
在这里插入图片描述

相同分组的task会被放在一起,我们看下
在这里插入图片描述
那我们都能为task配置哪些呢?我们去Task源码看下就行了
在这里插入图片描述

2.Task的执行详解

在这里插入图片描述
我们发现我们执行helloTask这个task,也会打印出helloTask2里面的输出内容,为什么呢?很简单,因为它们都是在配置阶段执行的,那么我们怎么让他们在执行阶段执行呢?调用doFirst或者doLast方法
在这里插入图片描述
我们看下结果
在这里插入图片描述

首先doFirstdoLast确实是在执行阶段执行的.然后就是在外面执行的doFirst或者doLast要优先比在闭包中执行,这两个方法可以对gradle中提供的已有的task进行扩展

下面我们就实战下,统计我们build的时间
思路:

  • 1.定义两个变量:开始执行时间和执行结束时间,两者差值就是我们要的结果
  • 2.找到第一个被执行的task,调用doFirst方法,获取开始时间
  • 3.找到最后被执行的task,执行doLast方法,获取结束时间
  • 4.两者做差
    在这里插入图片描述
    我们打印看下一共用了多长时间
    在这里插入图片描述

3.Task的依赖和执行顺序

在这里插入图片描述

3.1 Task依赖

我们首先定义三个task
在这里插入图片描述
我们先执行下什么都不依赖的taskC
在这里插入图片描述
只输出了taskC,后续我们会和这个作对比
我们想为我们的taskC指定依赖该怎么做呢?

第一种:在定义的时候添加dependsOn,就跟我们之前添加group一样

在这里插入图片描述
添加多个需要使用数组
在这里插入图片描述
我们执行下taskC
在这里插入图片描述

第二种:调用dependsOn方法

在这里插入图片描述

第三种:动态依赖

这里我们为了演示再新建几个task

在这里插入图片描述

然后我们通过TaskContainerfindAll方法找我符合我们的task,然后taskC依赖他们
在这里插入图片描述

我们执行下taskC
在这里插入图片描述

3.2 Task输入输出

在这里插入图片描述
TaskInputs:Task输入类,可以是任意数据类型和文件
TaskOutputs:Task输出类,只能是文件或者文件夹,同时也可以作为另外TaskTaskInputs
下面我们写一个小例子来学习下这两个方法
假设我们想输出一个xml文件.里面的内容包括版本号和版本信息,
在这里插入图片描述
首先我们新建三个扩展属性:
在这里插入图片描述
这里我们还需要定义一个File,就是我们的release.xml,如果不存在我们就手动创建下
在这里插入图片描述

然后我们就开始实现我们的读写功能,相对应的我们需要创建两个task,writeTaskreadTask
我们先写writeTask
我们要把我们之前定义的三个属性传给我们的task

    inputs.property('versionCode', this.versionCode)
    inputs.property('versionName', this.versionName)
    inputs.property('versionInfo', this.versionInfo)

还要指定输出

    //为task指定输出
    outputs.file this.destFile

下面就开始编写真正的逻辑,这段逻辑写在doLast{}

task writeTask {
    inputs.property('versionCode', this.versionCode)
    inputs.property('versionName', this.versionName)
    inputs.property('versionInfo', this.versionInfo)
    outputs.file this.destFile
    doLast {
    	// 返回一个map
        def data = inputs.getProperties() 
        File file = outputs.getFiles().getSingleFile()
        // 将map转为实体对象
        def versionMsg = new VersionMsg(data)
        def sw = new StringWriter()
        def xmlBuilder = new MarkupBuilder(sw)
        // 文件中没有内容
        if (file.text != null && file.text.size() <= 0) { 
            // 将xml数据写入到sw中
            xmlBuilder.releases { // <releases>
                release { // <releases>的子节点<release>
                    versionCode(versionMsg.versionCode)
                    // <release>的子节点<versionCode>1.0.0<versionCode>
                    versionName(versionMsg.versionName)
                    versionInfo(versionMsg.versionInfo)
                }
            }
            // 将sw里的内容写到文件中
            file.withWriter { writer ->
                writer.append(sw.toString())
            }
        } else { // 已经有其它版本信息了
            xmlBuilder.release {
                versionCode(versionMsg.versionCode)
                versionName(versionMsg.versionName)
                versionInfo(versionMsg.versionInfo)
            }
            def lines = file.readLines()
            def lengths = lines.size() - 1
            file.withWriter { writer ->
                lines.eachWithIndex { String line, int index ->
                    if (index != lengths) {
                        writer.append(line + '\r\n')
                    } else if (index == lengths) {
                        writer.append(sw.toString() + '\r\n')
                        writer.append(line + '\r\n')
                    }
                }
            }
        }
    }
}

task readTask {
    inputs.file destFile
    doLast {
        def file = inputs.files.singleFile
        println file.text
    }
}

然后写一个测试task依赖这两个task

task taskTest(dependsOn: [writeTask, readTask]) {
    doLast {
        println '任务执行完毕'
    }
}

这里有个地方要注意下,writeTask执行顺序是要优先于readTask

3.3 Task通过API指定执行顺序

  • mustRunAfter : 强行指定在某个或某些task执行之后才执行。
  • shouldRunAfter : 与mustRunAfter的作用一样,但不强制。

这里我们新建几个task来实践下
在这里插入图片描述

这里我们强制执行顺序为taskX,taskY,taskZ
我们打乱下执行顺序看下输出结果
在这里插入图片描述

4.挂接到构建生命周期

这个和我们之前讲解获取构建时长类似,我们这里是项目build完执行我们自定义的task
在这里插入图片描述

5.Task的类型

这个我们就需要去gradle官网去了解下了
官网
打开官网后,找到左侧的Task types
在这里插入图片描述

比如我们之前说的Copy
在这里插入图片描述

发布了87 篇原创文章 · 获赞 319 · 访问量 149万+

猜你喜欢

转载自blog.csdn.net/Greathfs/article/details/102809361