What kinds of objects can gradle.addListener accept, and how does Gradle decide which events it receives?
answer
- addListener inspects implemented interfaces
- one object → many event types
- TaskExecutionListener + TaskExecutionGraphListener etc.
- removeListener to unregister
- cache-incompatible mechanism
basics
~10 sgradle.addListener takes one object and inspects which listener interfaces it implements — e.g. TaskExecutionListener, TaskExecutionGraphListener, ProjectEvaluationListener, BuildListener — and routes the matching events to it. One object can implement several.
solid answer
~40 s`gradle.addListener(Object)` is a generic registration point. Gradle examines the supplied object's implemented listener interfaces and subscribes it to every event type it can handle. A single object may implement multiple interfaces — for instance a class implementing both `TaskExecutionListener` (per-task before/after) and `TaskExecutionGraphListener` (`graphPopulated`) will receive both kinds of callbacks. Recognized interfaces include `TaskExecutionListener`, `TaskExecutionGraphListener`, `ProjectEvaluationListener`, `BuildListener`, and `DependencyResolutionListener`. You remove a listener with `gradle.removeListener(obj)`. Because this whole mechanism relies on live mutable callbacks, it is configuration-cache incompatible; for execution observation the typed `OperationCompletionListener` route is preferred. `addListener` is the broad, one-call way to register cross-cutting observers when you're not targeting the configuration cache.
code
kotlin · 6 linesclass Multi : TaskExecutionListener, TaskExecutionGraphListener {
override fun graphPopulated(g: TaskExecutionGraph) { /* once */ }
override fun beforeExecute(t: Task) {}
override fun afterExecute(t: Task, s: TaskState) {}
}
gradle.addListener(Multi()) // receives both graph + per-task eventsgo deeper
Know addListener takes an object and routes events based on which listener interfaces it implements.
List the common interfaces it recognizes and that one object can implement several; mention removeListener.
Note the cache incompatibility and steer execution-observation toward OperationCompletionListener.
Discourage broad addListener-based observers in shared build logic; prefer narrowly-scoped, cache-safe services.
## A single registration, many event types `Gradle.addListener(Object listener)` is intentionally untyped. Rather than having a separate `addXListener` for every concern, Gradle inspects the object you pass and wires it up to **all listener interfaces it implements**. This is convenient: one object can be a one-stop observer. ## Interfaces it recognizes Among the listener interfaces routed through `addListener`: - `TaskExecutionListener` — `beforeExecute(task)` / `afterExecute(task, state)`. - `TaskExecutionGraphListener` — `graphPopulated(graph)` (graph readiness). - `ProjectEvaluationListener` — `beforeEvaluate` / `afterEvaluate` of projects. - `BuildListener` — coarse build phases (`settingsEvaluated`, `projectsLoaded`, `projectsEvaluated`, `buildFinished`). - `DependencyResolutionListener` — before/after dependency resolution of a configuration. If your object implements two of these, both sets of callbacks fire. ```kotlin class Observer : TaskExecutionListener, TaskExecutionGraphListener { override fun graphPopulated(graph: TaskExecutionGraph) { println("graph has ${graph.allTasks.size} tasks") } override fun beforeExecute(task: Task) {} override fun afterExecute(task: Task, state: TaskState) { println("${task.path}: didWork=${state.didWork}") } } gradle.addListener(Observer()) ``` ## Removing listeners `gradle.removeListener(obj)` unregisters the same object. There's rarely a need within a normal build, but long-lived tooling integrations may manage listener lifecycles explicitly. ## Scope Note the focus here is the *execution/graph* listeners: `TaskExecutionListener`, `TaskExecutionGraphListener`, and the `addListener` mechanism itself. Build-completion details (`buildFinished`) and project-evaluation details are handled by adjacent hooks; `addListener` simply happens to be the common door for several of them. ## Caveat All of these are live mutable callbacks — **not configuration-cache compatible**. For execution observation in cache-enabled builds, use `OperationCompletionListener` via `BuildEventsListenerRegistry` instead.
- If an object implements TaskExecutionListener and TaskExecutionGraphListener, which fires first?graphPopulated fires once at the end of configuration; then beforeExecute/afterExecute fire repeatedly during execution. So the graph callback precedes any per-task callback.
- How do you unregister a listener added with addListener?Call gradle.removeListener(theSameObject).
saying these in an interview costs you the question
- Thinking addListener requires you to specify the event type — it infers it from implemented interfaces.
- Assuming an object can only be one listener type at a time.