What is addTaskExecutionGraphListener and how does it relate to whenReady?
answer
- graphPopulated == same moment as whenReady
- listener = reusable object, closure = sugar
- TaskExecutionGraphListener single method
- NOT TaskExecutionListener (per-task, deprecated)
- build services replace per-task listeners
basics
~10 saddTaskExecutionGraphListener registers a TaskExecutionGraphListener whose graphPopulated method fires when the graph is ready — the same moment as whenReady. whenReady is just closure-based sugar for the same hook.
solid answer
~40 s`gradle.taskGraph.addTaskExecutionGraphListener(listener)` registers an explicit `TaskExecutionGraphListener`. Its `graphPopulated(TaskExecutionGraph)` callback fires at exactly the same point as `whenReady` — when the task execution graph has been built but before execution. The difference is purely ergonomic: `whenReady { graph -> }` is a convenient closure/Action registration, while the listener is a reusable object implementing an interface, useful when you want to share one listener instance across builds, unit-test it, or also implement other listener callbacks. Functionally both observe the graph-ready event and receive the same `TaskExecutionGraph`. The listener form historically also exposed `graphPopulated`; some older listener interfaces (like `TaskExecutionListener` for per-task beforeTask/afterTask) are different and are deprecated/removed in favor of build services and the configuration-cache-friendly APIs.
code
kotlin · 4 linesgradle.taskGraph.addTaskExecutionGraphListener { graph ->
// graphPopulated body via SAM conversion
println("About to execute: " + graph.allTasks.joinToString { it.path })
}go deeper
Know that addTaskExecutionGraphListener and whenReady do the same thing, just different syntax.
Name the graphPopulated method and explain when a reusable listener object beats an inline closure.
Distinguish it from deprecated per-task TaskExecutionListener and point to build services as the replacement.
Frame the choice in terms of plugin testability, configuration-cache compatibility, and the build-event listener API direction.
## Two ways to observe graph-ready Gradle exposes the same graph-populated event through two registration styles on `TaskExecutionGraph`: ### Closure / Action sugar ```kotlin gradle.taskGraph.whenReady { graph -> /* ... */ } ``` Concise; ideal for one-off build-script logic. ### Explicit listener ```kotlin class PlanLogger : TaskExecutionGraphListener { override fun graphPopulated(graph: TaskExecutionGraph) { println("Scheduled ${graph.allTasks.size} tasks") } } gradle.taskGraph.addTaskExecutionGraphListener(PlanLogger()) ``` The interface `TaskExecutionGraphListener` has a single method `graphPopulated(TaskExecutionGraph)`. It fires at the **identical** lifecycle moment as `whenReady`. ## When to prefer the listener - You have a **reusable, testable object** (e.g. shipped in a plugin) rather than inline script logic. - You want to register the same observer from plugin code with clear typing. - You need to keep a reference to remove or reason about it. ## Important distinction: not TaskExecutionListener Do **not** confuse `TaskExecutionGraphListener` (graph-ready, one shot) with the older per-task `TaskExecutionListener` (`beforeExecute`/`afterExecute` for *each* task). The per-task execution listeners are **deprecated/removed** in modern Gradle because they are incompatible with the configuration cache; the recommended replacements are **build services** (`BuildService`) and `OperationCompletionListener` via the build-event API. The graph-ready hook (`whenReady` / `addTaskExecutionGraphListener`) remains the supported way to react once to the populated graph. ## Same data, same timing Whichever you choose, you receive the same `TaskExecutionGraph` and can call `allTasks` and `hasTask`. The choice is about code organization, not capability.
- Does graphPopulated fire before or after whenReady closures?They observe the same graph-ready event; both run at that boundary. Don't rely on a strict ordering between independently registered callbacks for correctness.
- Why are per-task TaskExecutionListener beforeExecute/afterExecute discouraged?They are incompatible with the configuration cache and were deprecated/removed; build services and the build-event OperationCompletionListener are the supported replacements.
saying these in an interview costs you the question
- Confusing TaskExecutionGraphListener (graph-ready, once) with TaskExecutionListener (per-task, deprecated).
- Claiming the listener fires at a different lifecycle point than whenReady — it's the same graphPopulated moment.