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 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android Gradle(八)Task基础和自定义Task -> 正文阅读

[移动开发]Android Gradle(八)Task基础和自定义Task

一、前言

? ? ? ? 在Gradle中,学习和使用Task是我们必不可少的内容。什么是Task?Task就是一个操作,你可以用来移动复制文件、自定义输出打包apk文件名或者上传一些文件或者jar到Maven仓库等。再简单地说,可以理解成一个Java方法。Android中最常见的Task,如下:

task clean(type: Delete) {
    delete rootProject.buildDir
}

可以看到,他的任务就是删除根目录下的buildDir文件夹 。接下来,让我们看看如何创建一个任务😀

二、创建一个任务

PS:以下的代码都是放在build.gradle中运行,如果想在单独的gradle文件运行,必须apply进项目里才行,例如 apply from: 'custom.gradle'。

? ? ? ? 在Gradle中,创建一个任务的方式很简单,如下:

task printfHello{
    println "printfHello 配置阶段"
    doFirst {
        println "Hello doFirst"
    }
    doLast {
        println "Hello doLast"
    }
}

如上所示,一个简单的任务就创建成功了,其中doFirst,doLast分别代码在任务的执行前后对任务的操作。

?上面的代码等同于如下代码:

task("printfHello"){
    println "printfHello 配置阶段"
    doFirst {
        println "Hello doFirst"
    }
    doLast {
        println "Hello doLast"
    }
}
//或者
def Task customTask = task("customTask")
customTask.doFirst {
    println "customTask start"
}

如何运行我们的任务呢?

1.点击代码旁边的绿色标志

2.在Terminal下输入如下指令:

gradlew printfHello

效果如下:?

可以看到,分别输出了配置阶段的任务代码和运行阶段的任务代码。从此也能看出,一开始clean Task就在配置阶段进行文件夹的删除。
关于Gradle的生命周期可以看这里,其实也就三个阶段,初始化阶段? 》》配置阶段 》》运行阶段

接下来我们可以看下task对应的源码,如下:

Task task(String name, Closure configureClosure);

?其实task就是Project对象的一个方法,第一个参数是任务名,第二个参数是一个闭包,这个闭包的作用就是对我们创建的任务进行相关的配置和执行。

? ? ? ? 除了上面的方法,还可以通过TaskContaniner集合来创建。代码如下:

tasks.create("printHelloWorld"){
    doFirst {
        println "Hello World doFirst"
    }
    doLast {
        println "Hello World doLast"
    }
}

?这两种创建任务的方式作用都是一样的,只是创建的方式不一样。一般使用第一种,会比较简洁。

三、任务依赖

? ? ? ? 每个任务之间是有依赖的,可以方便我们控制任务执行的顺序。例如一个Apk的生成,肯定需要先把Java转成Class,再把Class转成Dex文件,然后再把Dex文件与其他资源文件合成一个Apk文件。下面让我们看看任务间是如何依赖的,如下:

//准备内存
task buildMemory{
    doFirst {
        println "buildMemory start"
    }
    doLast {
        println "buildMemory finish"
    }
}

//准备CPU
task buildCpu{
    doFirst {
        println "buildCpu start"
    }
    doLast {
        println "buildCpu finish"
    }
}

//组装电脑
task assembleComputer{
    dependsOn(buildCpu,buildMemory)
    doFirst {
        println "assembleComputer start"
    }
    doLast {
        println "assembleComputer finish"
    }
}

如上面的代码,依赖另外一个task的关键方法是dependsOn,参数是依赖的task任务,也就是先执行的任务。运行效果如下:

> Task :buildCpu
buildCpu start
buildCpu finish

> Task :buildMemory
buildMemory start
buildMemory finish

> Task :assembleComputer
assembleComputer start
assembleComputer finish

依赖任务的方式还有如下写法:

task assembleComputer(dependsOn: [buildCpu,buildMemory])

?四、自定义继承Task

? ? ? ? 不知道你会不会有疑惑,task有doFirst,doLast方法,那任务执行中的方法在哪里?如果想知道答案的话,继续往下看。先上一段代码,如下:

def customTask = task customtask(type:CustomTask)
customTask.doFirst {
    println "CustomTask doFirst"
}
customTask.doLast {
    println "CustomTask doLast"
}

abstract class CustomTask extends DefaultTask {

    @Override
    Task doFirst(Action<? super Task> action) {
        return super.doFirst(action)
    }

    @TaskAction
    def doSelf(){
        println "CustomTask doSelf"
    }
}

先解释一下几个关键:

  • type是一个关键字,用来引入一个存在的Task,例如我们创建的CustomTask
  • DefaultTask,用来提供给用户自定义Task的基类
  • @TaskAction是一个注解标注,意思是被标注的方法就是Task要执行的方法,可以多个。

执行代码效果图如下:

> Task :customtask
CustomTask doFirst
CustomTask doSelf
CustomTask doLast

可以看到,任务的执行前、执行中、执行后的逻辑都出来了。

那他是如何做到这样顺序执行的呢?

原理很简单,DefaultTask维护了一个actions的List,那只要我们按顺序添加doFirst、doSelf(把自己执行的代码叫doSelf)、doLast,然后便利执行actions List,那不久可以做到如上面的效果。

doFirst添加进actions List(往0下标下标插入)源码如下:

public Task doFirst(final Closure action) {
        taskMutator.mutate("Task.doFirst(Closure)", new Runnable() {
            @Override
            public void run() {
                getTaskActions().add(0, convertClosureToAction(action, "doFirst {} action"));
            }
        });
    }

doLast添加进actions List(往最后插入)源码如下:

public Task doLast(final Closure action) {
        taskMutator.mutate("Task.doLast(Closure)", new Runnable() {
            @Override
            public void run() {
                getTaskActions().add(convertClosureToAction(action, "doLast {} action"));
            }
        });
        return this;
    }

可以看到,doFirst下标的位置肯定是在doLast之前的,再来看看doSelf是如何执行的。

doSelf添加进actions List(往0下标下标插入)源码如下:

public void prependParallelSafeAction(final Action<? super Task> action) {
        if (action == null) {
            throw new InvalidUserDataException("Action must not be null!");
        }
        getTaskActions().add(0, wrap(action));
    }

看到这里,你会不会疑惑?也是往0下标插入,那如何保证顺序呢?

答案是肯定可以保证的,因为这个方法的调用是在解析@TaskAction标注的时候执行的,也就是此方法被执行时actions List里面的元素是空的。

?五、其他功能补充

5.1 强制排序

在你同时执行多个任务的时候,可能需要任务B必须在任务A执行完才能执行。代码如下:
taskB.mustRunAfter(taskA)   //表示taskB必须在taskA后执行
taskB.shouldRunAfter(taskA) //表示taskB应该在taskA后执行,这个相比较mustRunAfter,可能会出现意外的情况

示例如下:

task getBook{
    doLast {
        println "getBook finish"
    }
}

task learnEnglish{

    doFirst {
        println "learnEnglish start"
    }
    doLast {

        println "learnEnglish finish"
    }
}
learnEnglish.mustRunAfter(getBook)   //表示learnEnglish任务必须在getBook任务后执行

执行如下指令:

gradlew learnEnglish getBook

如果没有加mustRunAfter,那么就会按照代码顺序执行,先执行learnEnglishgetBook。加了mustRunAfter之后,执行效果如下:

?5.2?启用/禁止任务

? ? ? ? Task中有一个enable属性,表示启用或禁止任务,默认是true,表示启用;false表示禁止任务执行,执行时会被跳过。修改上面的getBook代码,增加enable为禁止,如下:

task getBook{
    enabled(false)
}

执行代码,getBook任务没有被执行到,效果图如下:

??5.3?任务的onlyIf

? ? ? ? Task中有一个onlyIf的方法,如果返回true,说明任务可以执行,否则就跳过。我们继续给getBook增加一个onlyIf方法,用来判断获取的书籍是不是英语书,如下代码:

getBook.onlyIf{
    def book  = "世界百科"
    if (book =="英语书"){
        return true
    }else {
        false
    }
}

执行代码,getBook任务没有被执行到,效果图如下:

PS:这个onlyIf方法可以使用在任何有Task的场景,不要局限在mustRunAfter,mustRunAfter只是控制Task的执行顺序。

??5.4?任务的分组和描述

? ? ? ? 在Task中,我们可以给Task分组和添加描述,可以让开发者更加直观的知道这个Task的作用。代码如下:

task learnEnglish{
    group(BasePlugin.BUILD_GROUP)
    description("这个一个learnEnglish Task")
}
  • group:给task分组,可以显示在对应的分组里,例如上面BUILD_GROUP,显示在build分组,其他的选项也是如此效果。
  • description:给task添加一个描述,可以通过gradlew tasks命令查看

Sync Now代码,在build中多了一个learnEnglish Task,

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章           查看所有文章
加:2022-05-21 19:06:35  更:2022-05-21 19:08:29 
 
开发: 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/25 1:45:25-

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