Marian Klühspies
Marian Klühspies

Reputation: 17637

Understanding different variants of declaring a task in Gradle

There are two different variants of declaring a task in Gradle.

1.

task myTask() {}

2.

task task3 << {}

To test how they behave, I´ve created a sample android project

apply plugin: 'com.android.application'

android {
    compileSdkVersion 22
    buildToolsVersion "21.1.2"

    defaultConfig {
        applicationId "com.android.gradletest"
        minSdkVersion 15
        targetSdkVersion 22
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:22.1.1'
}



task task1() {
    println "Task 1"
}

task task2() {
    println "Task 2"
}

task task3 << {
    println "Task 3"
}

task task4() {
    println "Task 4"
}

First attempt was executing Task 1

Task 1
Task 2
Task 4
:app:task1 UP-TO-DATE

BUILD SUCCESSFUL

Total time: 6.462 secs

Process finished with exit code 0

As you see, not just only Task 1 is executed, but the complete build WITHOUT Task 3.

Second attempt was running Task 3 directly:

Task 1
Task 2
Task 4
:app:task3
Task 3

BUILD SUCCESSFUL

Total time: 6.577 secs

Process finished with exit code 0

Result was again, the complete build seems to be triggered, but this time WITH Task 3 at the end.

Third attempt was simply building the complete project by pressing the run button of Android Studio

Task 1
Task 2
Task 4
:app:preBuild UP-TO-DATE
:app:preDebugBuild UP-TO-DATE
:app:checkDebugManifest
:app:preReleaseBuild UP-TO-DATE
:app:prepareComAndroidSupportAppcompatV72211Library UP-TO-DATE
:app:prepareComAndroidSupportSupportV42211Library UP-TO-DATE
:app:prepareDebugDependencies
:app:compileDebugAidl UP-TO-DATE
:app:compileDebugRenderscript UP-TO-DATE
:app:generateDebugBuildConfig UP-TO-DATE
:app:generateDebugAssets UP-TO-DATE
:app:mergeDebugAssets UP-TO-DATE
:app:generateDebugResValues UP-TO-DATE
:app:generateDebugResources UP-TO-DATE
:app:mergeDebugResources UP-TO-DATE
:app:processDebugManifest UP-TO-DATE
:app:processDebugResources UP-TO-DATE
:app:generateDebugSources UP-TO-DATE
:app:processDebugJavaRes UP-TO-DATE
:app:compileDebugJava
Note: Recompile with -Xlint:deprecation for details.
:app:compileDebugNdk UP-TO-DATE
:app:compileDebugSources
:app:preDexDebug
:app:dexDebug
:app:validateDebugSigning
:app:packageDebug
:app:zipalignDebug
:app:assembleDebug
Information:BUILD SUCCESSFUL

As you can see, everything gets triggered, except Task 3!

Now I have two questions:

  1. What is the << task declaration ment for, when we aren´t able to run it standalone and it is not triggered within the build process?
  2. Why is it triggering multiple tasks when I execute just one out of the Task Menu and how do I execute just a single one then? enter image description here

Upvotes: 0

Views: 767

Answers (1)

Amnon Shochot
Amnon Shochot

Reputation: 9376

Gradle build goes through 3 phases:

  1. Initialization - determine which projects are going to take part in the build, and creates a Project instance for each of these projects.
  2. Configuration - configure project objects and specifically the tasks to be executed.
  3. Execution - executing the subset of the tasks created and configured during the configuration phase.

Now, a task definition contains 3 stages:

task myTask {
    // Configuration scope
    // will be executed during the configuration phase

    doFirst {
        // Will be executed during the execution phase before the task defined behavior
    }

    doLast {
        // Will be executed during the execution phase after the task defined behavior
    } 
}

So, when you define a task like this:

task task1() {
    println "Task 1"
}

Since the println statement is part of the configuration scope it will be executed in the configuration phase, regardless if this task was chosen to execute or not.

Now, using the << operator for defining a task is actually a shortcut for defining the doLast closure for the task, i.e.

task task3 << {
    println "Task 3"
}

is equivalent to:

task task3 {
    doLast {
        println "Task 3"
    }
}

Then, per my explanation above, in this case the println statement will only be executed during the execution phase, in case task3 has to be executed as was determined during the configuration phase.

If you're interested to learn more about it I would highly recommend you to go through the following sections in Gradle user guide:

  1. Build Script Basics
  2. The Build Lifecycle

Upvotes: 1

Related Questions