Listeners
NOTE Defining listeners in
plugin.xml
is supported starting with version 2019.3 of the platform.NOTE Listener implementations must be stateless and may not implement life-cycle (e.g.,
Disposable
).
Listeners allow plugins to declaratively subscribe to events delivered through the message bus (see Messaging infrastructure for details).
You can define both application- and project-level listeners.
Declarative registration of listeners allows you to achieve better performance than registering listeners from code. The advantage is because listener instances get created lazily - the first time an event is sent to the topic - and not during application startup or project opening.
Defining Application-Level Listeners
To define an application-level listener, add the following section to your plugin.xml
:
<applicationListeners>
<listener class="myPlugin.MyListenerClass" topic="BaseListenerInterface"/>
</applicationListeners>
The topic
attribute specifies the listener interface corresponding to the type of events you want to receive.
Usually, this is the interface used as the type parameter of the Topic
instance for the type of events.
The class
attribute specifies the class in your plugin that implements the listener interface and receives the events.
As a specific example, if you want to receive events about all virtual file system changes, you need to implement the BulkFileListener
interface, corresponding to the topic VirtualFileManager.VFS_CHANGES
.
To subscribe to this topic from code, you could use something like the following snippet:
messageBus.connect().subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() {
@Override
public void after(@NotNull List<? extends VFileEvent> events) {
// handle the events
}
});
To use declarative registration, you no longer need to reference the Topic
instance.
Instead, you refer directly to the listener interface class:
<applicationListeners>
<listener class="myPlugin.MyVfsListener"
topic="com.intellij.openapi.vfs.newvfs.BulkFileListener"/>
</applicationListeners>
Then you provide the listener implementation as a top-level class:
public class MyVfsListener implements BulkFileListener {
@Override
public void after(@NotNull List<? extends VFileEvent> events) {
// handle the events
}
}
Defining Project-Level Listeners
Project-level listeners are registered in the same way, except that the top-level tag is <projectListeners>
.
They can be used to listen to project-level events, for example, tool window operations:
<projectListeners>
<listener class="MyToolwindowListener"
topic="com.intellij.openapi.wm.ex.ToolWindowManagerListener" />
</projectListeners>
The class implementing the listener interface can define a one-argument constructor accepting a Project
, and it will receive the instance of the project for which the listener is created:
public class MyToolwindowListener implements ToolWindowManagerListener {
private final Project project;
public MyToolwindowListener(Project project) {
this.project = project;
}
@Override
public void stateChanged() {
// handle the state change
}
}
Additional Attributes
Registration of listeners can be restricted using the following attributes:
os
- allows to restrict listener to given OS, e.g.,os="windows"
for Windows only (2020.1 and later)activeInTestMode
- set tofalse
to disable listener ifcom.intellij.openapi.application.Application.isUnitTestMode()
==true
activeInHeadlessMode
- set tofalse
to disable listener ifcom.intellij.openapi.application.Application.isHeadlessEnvironment()
==true
. Also, coversactiveInTestMode
as test mode implies headless mode.