# Event listeners (/en/realtime-media/rtm/build/send-and-receive-messages/add-event-listener/flutter)

> For AI agents: see the complete documentation index at [llms.txt](/llms.txt).

To receive message and event notifications when you subscribe to or join channels, you add an event listener. An event listener is triggered by the SDK to inform the client about Signaling events and state changes. The listener enables you to respond to events like successful connection to Signaling, token expiration, received messages, and other presence, storage, and lock events.

## Prerequisites

Ensure that you have integrated the Signaling SDK in your project and implemented the framework functionality from the [SDK quickstart](../../index) page.

## Implement event listeners

This section shows how to use the Signaling SDK to implement event listeners.

### Add an event listener

Signaling uses an `RtmEventListener` instance to process messages and event notifications. Each message and event notification has a corresponding event handler, where you implement your own processing logic. Refer to the following code to create and use an instance of `RtmEventListener`:

```dart
rtmClient.addListener(
    // Handle message event
    message: (MessageEvent event) {
        const channelType = event.channelType;      // The channel type, 'STREAM' 'MESSAGE', or 'USER'
        const channelName = event.channelName;      // The name of the channel that this message came from
        const topicName = event.channelTopic;       // (Stream channel only) The name of the topic that this message came from
        const messageType = event.messageType;      // The message type, 'STRING' or 'BINARY'
        const customType = event.customType;        // User defined type
        const publisher = event.publisher;          // The message publisher
        const message = event.message;              // The message payload
        const timestamp = event.timestamp;          // Event timestamp
    },
    // Handle presence event
    presence: (PresenceEvent event) {
        const action = event.type;                  // The event type, should be one of 'SNAPSHOT', 'INTERVAL', 'JOIN', 'LEAVE', 'TIMEOUT、'STATE_CHANGED', 'OUT_OF_SERVICE'.
        const channelType = event.channelType;      // The channel type, should be "STREAM", "MESSAGE" or "USER"
        const channelName = event.channelName;      // The name of the channel this event came from
        const publisher = event.publisher;          // The user who triggered this even
        const states = event.stateItems;            // User state payload, only for the stateChanged event
        const interval = event.interval;            // Interval payload, only for the interval event
        const snapshot = event.snapshot;            // Snapshot payload, only for the snapshot event
        const timestamp = event.timestamp;          // Event timestamp
    },
   // Handle topic event
    topic: (TopicEvent event) {
        const action = event.type;                  // The event type, should be one of 'SNAPSHOT', 'JOIN', 'LEAVE'
        const channelName = event.channelName;      // The name of the channel this event came from
        const publisher = event.publisher;          // The user who triggered this even
        const topicInfos = event.topicInfos;        // Topic information payload
        const timestamp = event.timestamp;          // Event timestamp
    },
    // Handle storage event
    storage: (StorageEvent event) {
        const channelType = event.channelType;      // The channel type, should be "STREAM", "MESSAGE" or "USER"
        const target = event.target;                // Which channel or user triggered this event
        const storageType = event.storageType;      // The storage type, should be 'USER'、'CHANNEL'
        const action = event.eventType;             // The event type, should be one of "SNAPSHOT"、"SET"、"REMOVE"、"UPDATE" or "NONE"
        const data = event.data;                    // USER_METADATA or CHANNEL_METADATA payload
        const timestamp = event.timestamp;          // Event timestamp
    },
    // Handle lock event
    lock: (LockEvent event) {
        const channelType = event.channelType;      // The channel type, should be "STREAM", "MESSAGE" or "USER"
        const channelName = event.channelName;      // The name of the channel this event came from
        const action = event.evenType;              // The action type, should be one of 'SET'、'REMOVED'、'ACQUIRED'、'RELEASED'、'EXPIRED'、'SNAPSHOT'
        const lockDetailList = event.lockDetailList;    // Lock event payload
    const timestamp = event.timestamp;              // Event timestamp
    },
    // Handle link state event
    linkState: (LinkStateEvent event) {
        const currentState = event.currentState;    // The current link state
        const previousState = event.previousState;  // The previous link state
        const serviceType = event.serviceType;      // The service type, Should be "stream" or "message".
        const operation = event.operation;          // Which operation triggered this state changed
        const reason = event.reason;                // The reason for this state change
        const affectedChannels = event.affectedChannels;  // Which channels are affected
        const unrestoredChannels = event.unrestoredChannels;    // Which channels are unrestored
        const isResumed = event.isResumed;
        const timestamp = event.timestamp;          // Event timestamp
    },
    // Handle token event
    token : (TokenEvent event) {
        const channelName = event.channelName;      // The channel for which the token will expire
    });
```

<CalloutContainer type="info">
  <CalloutDescription>
    The `message` field in `MessageEvent` is of type `Uint8List`. When you receive a string message, use the `utf8.decode()` method from the `dart:convert` library to convert it to a `String`.

    ```dart
    // Convert message from Uint8List to a String
    String message = utf8.decode(event.message!);
    ```
  </CalloutDescription>
</CalloutContainer>

### Remove event listeners

To avoid performance degradation caused by memory leaks, errors, and null pointer exceptions, best practice is to unregister an event handler when you no longer need to use it. To be able to unregister an event listener, avoid using anonymous functions when adding event listeners. The following code shows how to add and remove event listeners:

```dart
// Define a message event handling function
void onMessageReceived(MessageEvent event) {
  print('Received message event: $event');
}

// Register the message event listener
rtmClient.addListener(
  message: onMessageReceived
);

// Remove the message event listener
rtmClient.removeListener(
  message: onMessageReceived
);
```

### Signaling events

Signaling SDK offers the following events:

| Event Listener | Description                                                                                                                                                                                                                                                                                                                     |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `message`      | Receive message notifications from all the message channels you have subscribed to, or topic message notifications subscribed to from all the stream channels you have joined. The event payload data includes information such as channel name, channel type, topic name, event sender, and message payload data type.         |
| `presence`     | Receive online status event notifications of remote users in all message channels you have subscribed to and stream channels you have joined. The event payload data includes channel name, channel type, event type, event sender, user temporary status data, and other information.                                          |
| `topic`        | Receive notifications of topic change events in all the stream channels you have joined. The event payload data includes information such as channel name, event type, topic name, and event sender.                                                                                                                            |
| `storage`      | Receive all channel metadata event notifications in all message channels you have subscribed to and stream channels you have joined, as well as user metadata event notifications from all subscribed users. The event payload data includes information such as channel name, channel type, event type, and specific metadata. |
| `lock`         | Receive all lock event notifications in the message channel you have subscribed to and stream channel you have joined. The event payload data contains information such as channel name, channel type, event type, and lock details.                                                                                            |
| `linkState`    | Receive event notifications for client network connection status changes, including the connection status before and after the change, service type, operation type that caused the change, reason for the change, channel list, and other information.                                                                         |
| `token`        | Receive event notifications when the client token is about to expire.                                                                                                                                                                                                                                                           |

For details on the parameters passed in by each event, refer to [Event listeners](/en/api-reference/api-ref/signaling#event-listeners) in the API reference.

    
  
      
  
      
  
      
  
      
  
