# 添加事件监听 (/zh-CN/realtime-media/rtm/build/messaging/add-event-listener)

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

如需收到消息和事件通知，你需要先实现事件监听程序，然后订阅或者加入你想要接收消息或事件通知的频道。

## 添加事件监听 [#添加事件监听]

RTM 采用统一入口的方式处理消息和事件通知，每一种消息和事件通知都有对应的事件处理程序入口，你可以在其中实现自己的业务处理逻辑：

<_PlatformTabsGroup>
<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="android" />
```java
RtmEventListener eventListener = new RtmEventListener() {
      @Override
      public void onMessageEvent(MessageEvent event) {
      }

      @Override
      public void onPresenceEvent(PresenceEvent event) {
      }

      @Override
      public void onTopicEvent(TopicEvent event) {
      }

      @Override
      public void onLockEvent(LockEvent event) {
      }

      @Override
      public void onStorageEvent(StorageEvent event) {
      }

      @Override
      public void onLinkStateEvent(LinkStateEvent event) {
          // Your link state change event handler
      }

      @Override
      public void onTokenPrivilegeWillExpire(String channelName) {
      }
    };
RtmConfig rtmConfig = new RtmConfig();
rtmConfig.eventListener = eventListener;
mRtmClient = RtmClient.create(rtmConfig);
```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="ios" />
```objc
// define RTM Event Listener
@interface RtmListener : NSObject <AgoraRtmClientDelegate>

@end

@implementation RtmListener

// triggered when received message from remote
- (void)rtmKit:(AgoraRtmClientKit *)rtmKit didReceiveMessageEvent:(AgoraRtmMessageEvent *)event {
    NSString* channel = event.channelName;
    AgoraRtmChannelType channel_type = event.channelType;
    if (channel_type == AgoraRtmChannelTypeStream) {
        NSString* topic = event.channelTopic; // if message from stream channel, user can get topic name
    }

    if (event.message.rawData != nil) {
        NSData* message =event.message.rawData; // get binary message
    } else {
        NSString* message = event.message.stringData; // get string message
    }
    NSString* publisher = event.publisher;

}

// triggered when channel lock info changed
- (void)rtmKit:(AgoraRtmClientKit *)rtmKit didReceiveLockEvent:(AgoraRtmLockEvent *)event {
    NSString* channel = event.channelName;
    AgoraRtmChannelType channel_type = event.channelType;
    AgoraRtmLockEventType event_type = event.eventType;
    if (event.lockDetailList != nil) {
        NSArray<AgoraRtmLockDetail *> *lock_details = event.lockDetailList; //get detail lock info

    }
}

// triggered when prensence info changed
- (void)rtmKit:(AgoraRtmClientKit *)rtmKit didReceivePresenceEvent:(AgoraRtmPresenceEvent *)event {
    NSString* channel = event.channelName;
    AgoraRtmChannelType channel_type = event.channelType;
    AgoraRtmPresenceEventType event_type = event.type;
    NSString* publisher = event.publisher;
    if (event_type  == AgoraRtmPresenceEventTypeInterval) {
        AgoraRtmPresenceIntervalInfo* interval = event.interval;
    }else if (event_type == AgoraRtmPresenceEventTypeSnapshot) {
        NSArray<AgoraRtmUserState *> * snapshot = event.snapshot;
    } else {
        NSArray<AgoraRtmStateItem *> *states = event.states;
    }
}

// triggered when subscribed strorage changed
-(void)rtmKit:(AgoraRtmClientKit *)rtmKit didReceiveStorageEvent:(AgoraRtmStorageEvent *)event {
    AgoraRtmStorageType storage_type = event.storageType;
    if (storage_type == AgoraRtmStorageTypeChannel) {
        NSString* channel = event.target;
        AgoraRtmChannelType channel_type = event.channelType;
    } else {
        NSString* user = event.target;
    }
    AgoraRtmMetadata* data = event.data;
}

// triggered when token will expire
- (void)rtmKit:(AgoraRtmClientKit *)rtmKit tokenPrivilegeWillExpire:(NSString *)channel {
    if (channel != nil) {
        //renew specific stream channel's token
    } else {
        // renew rtm client's token
    }
}

// triggered when link state changed
- (void)rtmKit:(AgoraRtmClientKit *)rtmKit didReceiveLinkStateEvent:(AgoraRtmLinkStateEvent *)event {
    if (event.serviceType == AgoraRtmServiceTypeStream) {
        // receive stream channel link event
    } else {
        // receive message link event
    }
}
@end

AgoraRtmClientConfig* rtm_cfg = [[AgoraRtmClientConfig alloc] initWithAppId:@"your_appid" userId:@"your_userid"];

// add event listener
RtmListener* handler =  [[RtmListener alloc] init];
NSError* initError = nil;
AgoraRtmClientKit* rtm = [[AgoraRtmClientKit alloc] initWithConfig:rtm_cfg delegate:handler error:&initError];
```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="web" />
```javascript
// Handle message event
rtm.addEventListener("message", event => {
    const channelType = event.channelType;      // The channel type need to be "STREAM", "MESSAGE" or "USER".
    const channelName = event.channelName;      // The name of the channel that this message comes from.
    const topic = event.topicName;              // (Stream channel only) The name of the topic that this message comes from.
    const messageType = event.messageType;      // The message type need to be "STRING" or "BINARY".
    const customType = event.customType;        // User defined type.
    const publisher = event.publisher;          // Message publisher.
    const message = event.message;              // Message payload.
    const timestamp = event.timestamp;          // Event timestamp
});
// Handle presence event
rtm.addEventListener("presence", event => {
    const action = event.eventType;             // Which action it is ,should be one of 'SNAPSHOT'、'INTERVAL'、'JOIN'、'LEAVE'、'TIMEOUT、'STATE_CHANGED'、'OUT_OF_SERVICE'.
    const channelType = event.channelType;      // Which channel type it is, Should be "STREAM", "MESSAGE" or "USER".
    const channelName = event.channelName;      // Which channel does this event come from
    const publisher = event.publisher;          // Who trigger this event
    const states = event.stateChanged;          // User state payload, only for stateChanged event
    const interval = event.interval;            // Interval payload, only for interval event
    const snapshot = event.snapshot;            // Snapshot payload, only for snapshot event
    const timestamp = event.timestamp;          // Event timestamp
});
// Handle topic event
rtm.addEventListener("topic", event => {
    const action = event.evenType;              // Which action it is ,should be one of 'SNAPSHOT'、'JOIN'、'LEAVE'.
    const channelName = event.channelName;      // Which channel does this event come from
    const publisher = event.userId;             // Who trigger this event
    const topicInfos = event.topicInfos;        // Topic information payload
    const totalTopics = event.totalTopics;      // How many topics
    const timestamp = event.timestamp;          // Event timestamp
});
// Handle storage event
rtm.addEventListener("storage", event => {
    const channelType = event.channelType;      // Which channel type it is, Should be "STREAM", "MESSAGE" or "USER".
    const channelName = event.channelName;      // Which channel does this event come from
    const publisher = event.publisher;          // Who trigger this event
    const storageType = event.storageType;      // Which category the event is, should be 'USER'、'CHANNEL'
    const action = event.eventType;             // Which action it is ,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
rtm.addEventListener("lock", event => {
    const channelType = event.channelType;      // Which channel type it is, Should be "STREAM", "MESSAGE" or "USER".
    const channelName = event.channelName;      // Which channel does this event come from
    const publisher = event.publisher;          // Who trigger this event
    const action = event.evenType;              // Which action it is ,should be one of 'SET'、'REMOVED'、'ACQUIRED'、'RELEASED'、'EXPIRED'、'SNAPSHOT'
    const lockName = event.lockName;            // Which lock it effect
    const ttl = event.ttl;                      // The ttl of this lock
    const snapshot = event.snapshot;            // Snapshot payload
    const owner = event.owner;                  // The owner of this lock
    const timestamp = event.timestamp;          // Event timestamp
});
// Handle link state change event
rtm.addEventListener("linkState", event => {
    const currentState = event.currentState;          // Current link state
    const previousState = event.previousState;        // Previous link state
    const serviceType = event.serviceType;            // Service type
    const operation = event.operation;                // Operation that triggered this event
    const reason = event.reason;                      // Reason for the state change
    const affectedChannels = event.affectedChannels;  // Affected channels
    const timestamp = event.timestamp;                // Event timestamp
    const isResumed = event.isResumed;                // Whether the connection resumed
});
// Handle token privilege will expire event
rtm.addEventListener("tokenPrivilegeWillExpire", (channelName) => {
    const channelName = channelName;            // Which Channel Token Will Expire
});
```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="harmonyos" />
```typescript
import {
  MessageEvent,
  PresenceEvent,
  TopicEvent,
  StorageEvent,
  LockEvent,
  LinkStateEvent,
  TokenEvent
} from '@shengwang/rtm-full';

// Handle message event
rtmClient.addEventListener('message', (event: object) => {
  const msgEvent = event as MessageEvent;
  const channelType = msgEvent.channelType;      // The channel type: MESSAGE or STREAM
  const channelName = msgEvent.channelName;      // The name of the channel
  const topic = msgEvent.channelTopic;           // (Stream channel only) The topic name
  const messageType = msgEvent.messageType;      // The message type: STRING or BINARY
  const customType = msgEvent.customType;        // User defined type
  const publisher = msgEvent.publisher;          // Message publisher
  const message = msgEvent.message;              // Message payload (string or Uint8Array)
  const timestamp = msgEvent.timestamp;          // Event timestamp
  // Your business logic
});

// Handle presence event
rtmClient.addEventListener('presence', (event: object) => {
  const presenceEvent = event as PresenceEvent;
  const eventType = presenceEvent.eventType;          // Event type: SNAPSHOT, INTERVAL, JOIN, LEAVE, etc.
  const channelType = presenceEvent.channelType;      // Channel type: MESSAGE or STREAM
  const channelName = presenceEvent.channelName;      // Channel name
  const publisher = presenceEvent.publisher;          // Who triggered this event
  const stateChanged = presenceEvent.stateChanged;    // Changed state items
  const interval = presenceEvent.interval;            // Interval info (only for INTERVAL type)
  const snapshot = presenceEvent.snapshot;            // Snapshot info (only for SNAPSHOT type)
  const timestamp = presenceEvent.timestamp;          // Event timestamp
  // Your business logic
});

// Handle topic event
rtmClient.addEventListener('topic', (event: object) => {
  const topicEvent = event as TopicEvent;
  const eventType = topicEvent.eventType;          // Event type: SNAPSHOT, REMOTE_JOIN, REMOTE_LEAVE
  const channelName = topicEvent.channelName;      // Channel name
  const publisher = topicEvent.publisher;          // Who triggered this event
  const topicInfos = topicEvent.topicInfos;        // Topic information array
  const timestamp = topicEvent.timestamp;          // Event timestamp
  // Your business logic
});

// Handle storage event
rtmClient.addEventListener('storage', (event: object) => {
  const storageEvent = event as StorageEvent;
  const eventType = storageEvent.eventType;          // Event type: SNAPSHOT, SET, UPDATE, REMOVE
  const storageType = storageEvent.storageType;      // Storage type: USER or CHANNEL
  const channelType = storageEvent.channelType;      // Channel type (for channel metadata)
  const target = storageEvent.target;                // Channel name or user ID
  const data = storageEvent.data;                    // Metadata
  const timestamp = storageEvent.timestamp;          // Event timestamp
  // Your business logic
});

// Handle lock event
rtmClient.addEventListener('lock', (event: object) => {
  const lockEvent = event as LockEvent;
  const eventType = lockEvent.eventType;          // Event type: SNAPSHOT, LOCK_SET, LOCK_ACQUIRED, etc.
  const channelName = lockEvent.channelName;      // Channel name
  const channelType = lockEvent.channelType;      // Channel type
  const lockDetails = lockEvent.lockDetails;      // Lock details array
  const timestamp = lockEvent.timestamp;          // Event timestamp
  // Your business logic
});

// Handle link state event
rtmClient.addEventListener('linkState', (event: object) => {
  const linkEvent = event as LinkStateEvent;
  const currentState = linkEvent.currentState;    // Current link state
  const previousState = linkEvent.previousState;  // Previous link state
  const serviceType = linkEvent.serviceType;      // Service type: MESSAGE or STREAM
  const operation = linkEvent.operation;          // Operation that triggered this event
  const reason = linkEvent.reason;                // Reason description
  const affectedChannels = linkEvent.affectedChannels;      // Affected channels
  const unrestoredChannels = linkEvent.unrestoredChannels;  // Unrestored channels
  const isResumed = linkEvent.isResumed;          // Whether connection is resumed
  const timestamp = linkEvent.timestamp;          // Event timestamp
  // Your business logic
});

// Handle token event
rtmClient.addEventListener('token', (event: object) => {
  const tokenEvent = event as TokenEvent;
  const eventType = tokenEvent.eventType;          // Token event type
  const reason = tokenEvent.reason;                // Event reason
  const affectedResources = tokenEvent.affectedResources;  // Affected resources
  const timestamp = tokenEvent.timestamp;          // Event timestamp
  // Your business logic
});
```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="unity" />
```csharp
// add message event listener
rtmClient.OnMessageEvent += newMessageEvent =>
{
    var channelName = newMessageEvent.channelName;
    var channelType = newMessageEvent.channelType;
    var topic = newMessageEvent.channelTopic;
    var publisher = newMessageEvent.publisher;
    var messageType = newMessageEvent.messageType;
    var message = newMessageEvent.message;
    var customType = newMessageEvent.customType;
    // your Logic
};

// add presence event listener
rtmClient.OnPresenceEvent += newPresenceEvent =>
{
    var channelName = newPresenceEvent.channelName;
    var channelType = newPresenceEvent.channelType;
    var eventType = newPresenceEvent.type;
    var publisher = newPresenceEvent.publiser;
    var stateItems = newPresenceEvent.stateItems;
    var interval = newPresenceEvent.interval;
    var snapshot = newPresenceEvent.snapshot;
    // your Logic
};

// add topic event listener
rtmClient.OnTopicEvent += newTopicEvent =>
{
    var channelName = newTopicEvent.channelName;
    var eventType = newTopicEvent.type;
    var publisher = newTopicEvent.publisher;
    var topicInfos = newTopicEvent.topicInfos;
    if (topicInfos != null)
    {
        // your logic
    }
};

// add storage event listener
rtmClient.OnStorageEvent += newStorageEvent =>
{
    var channelName = newStorageEvent.channelName;
    var channelType = newStorageEvent.channelType;
    var eventType = newStorageEvent.eventType;
    var category = newStorageEvent.target;
    var data = newStorageEvent.data;
    if (data != null)
    {
        // your logic
    }
};

// add lock event listener
rtmClient.OnLockEvent += newLockEvent =>
{
    var channelName = newLockEvent.channelName;
    var channelType = newLockEvent.channelType;
    var eventType = newLockEvent.eventType;
    var LockDetail = newLockEvent.lockDetailList;
    if( LockDetail != null )
    {
        // your logic
    }
};

// add OnConnectionStateChange event listener
rtmClient.OnConnectionStateChanged +=(channelName, state, reason ) =>
{
    Debug.Log(string.Format("OnConnectionStateChanged channelName {0}: state:{1} reason:{2}", channelName, state, reason);
    // your logic
};

// add OnTokenPrivilegeWillExpire event listener
rtmClient.OnTokenPrivilegeWillExpire += channelName =>
{
    Debug.Log(string.Format("OnTokenPrivilegeWillExpire channelName {0}", channelName));
    // your logic
};
```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="flutter" />
```dart showLineNumbers
rtmClient.addListener(
    // Handle message event
    message: (MessageEvent event) {
        const channelType = event.channelType;                  // The channel type need to be "STREAM" or "MESSAGE".
        const channelName = event.channelName;                  // The name of the channel that this message comes from.
        const topicName = event.channelTopic;                   // (Stream channel only) The name of the topic that this message comes from.
        const messageType = event.messageType;                  // The message type need to be "STRING" or "BINARY".
        const customType = event.customType;                    // User defined type.
        const publisher = event.publisher;                      // Message publisher.
        const message = event.message;                          // Message payload.
        const timestamp = event.timestamp;                      // Message send timestamp.
    },
    // Handle presence event
    presence: (PresenceEvent event) {
        const action = event.type;                              // Which action it is ,should be one of 'SNAPSHOT'、'INTERVAL'、'JOIN'、'LEAVE'、'TIMEOUT、'STATE_CHANGED'、'OUT_OF_SERVICE'.
        const channelType = event.channelType;                  // Which channel type it is, Should be "STREAM" or "MESSAGE".
        const channelName = event.channelName;                  // Which channel does this event come from
        const publisher = event.publisher;                      // Who trigger this event
        const states = event.stateItems;                        // User state payload, only for stateChanged event
        const interval = event.interval;                        // Interval payload, only for interval event
        const snapshot = event.snapshot;                        // Snapshot payload, only for snapshot event
        const timestamp = event.timestamp;                      // event trigger timestamp.
    },
   // Handle topic event
    topic: (TopicEvent event) {
        const action = event.type;                              // Which action it is ,should be one of 'SNAPSHOT'、'JOIN'、'LEAVE'.
        const channelName = event.channelName;                  // Which channel does this event comes from
        const publisher = event.publisher;                      // Who trigger this event
        const topicInfos = event.topicInfos;                    // Topic information payload
        const timestamp = event.timestamp;                      // event trigger timestamp.
    },
    // Handle storage event
    storage: (StorageEvent event) {
        const channelType = event.channelType;                  // Which channel type it is, Should be "STREAM" or "MESSAGE".
        const target = event.target;                            // Which channel or who trigger this event
        const storageType = event.storageType;                  // Which category the event is, should be 'USER'、'CHANNEL'
        const action = event.eventType;                         // Which action it is ,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 trigger timestamp.
    },
    // Handle lock event
    lock: (LockEvent event) {
        const channelType = event.channelType;                  // Which channel type it is, Should be "STREAM" or "MESSAGE".
        const channelName = event.channelName;                  // Which channel does this event come from
        const action = event.evenType;                          // Which action it is ,should be one of 'SET'、'REMOVED'、'ACQUIRED'、'RELEASED'、'EXPIRED'、'SNAPSHOT'
        const lockDetailList = event.lockDetailList;            // lock event payload
        const timestamp = event.timestamp;                      // event trigger timestamp.
    },
    // Handle link state event
    linkState: (LinkStateEvent event) {
        const currentState = event.currentState;                // What is current link state
        const previousState = event.previousState;              // What is previous link state
        const serviceType = event.serviceType;                  // Which service type it is, Should be "stream" or "message".
        const operation = event.operation;                      // Which operation trigger this state changed
        const reason = event.reason;                            // Which reason trigger this state changed
        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 trigger timestamp.
    },
    // Handle token event
    token : (TokenEvent event) {
        const channelName = event.channelName;                  // Which channel's token token will expire, if it is '', message service token will expire or stream service token will expire
    });
```

:::info[消息格式转换]
`MessageEvent` 中的 `message` 字段为 `Uint8List` 类型，当你收到字符串类型的消息后，可以使用 `dart:convert` 库中的 `utf8.decode()` 方法将其转换成 `String` 类型：

``` dart
// convert Uint8List to String. ! means forced conversion
String message = utf8.decode(event.message!);
```

:::
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="cpp" />
```cpp
class RtmEventHandler: public IRtmEventHandler {
    void onMessageEvent(const MessageEvent &event) override {}
    void onTopicEvent(const TopicEvent &event) override {}
    void onLinkStateEvent(const LinkStateEvent& event) override {}
    void onLoginResult(RTM_ERROR_CODE errorCode) override {}
    void onStorageEvent(const StorageEvent &event) override {}
    void onLockEvent(const LockEvent &event) override {}
}

RtmConfig config;
config.appId = "your_appid";
config.userId = "your_name";
config.eventHandler = new RtmEventHandler();

uint64_t requestId;
IRtmClient* rtmClient = createAgoraRtmClient(config, requestId);
if (!rtmClient || errorCode != 0) {
  // create rtm client failed
}
```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="swift" />
```swift
class RtmListener: NSObject, AgoraRtmClientDelegate {

    func rtmKit(_ rtmKit: AgoraRtmClientKit, didReceiveLinkStateEvent event: AgoraRtmLinkStateEvent) {
        // code
    }

    func rtmKit(_ rtmKit: AgoraRtmClientKit, didReceiveMessageEvent event: AgoraRtmMessageEvent) {
        // code
    }

    func rtmKit(_ rtmKit: AgoraRtmClientKit, didReceiveLockEvent event: AgoraRtmLockEvent) {
        // code
    }

    func rtmKit(_ rtmKit: AgoraRtmClientKit, didReceiveTopicEvent event: AgoraRtmTopicEvent) {
        // code
    }
    func rtmKit(_ rtmKit: AgoraRtmClientKit, didReceiveStorageEvent event: AgoraRtmStorageEvent) {
        // code
    }

    func rtmKit(_ rtmKit: AgoraRtmClientKit, tokenPrivilegeWillExpire channel: String?) {
        // code
    }
}

do {
    let config = AgoraRtmClientConfig(appId: "yourAppId", userId: "uniqueUserId")
    let listener = RtmListener()
    // Initializing the RTM client
    let rtmClient = try AgoraRtmClientKit(config, delegate: listener)
    if rtmClient != nil {
        print("RTM Client initialized successfully!")
    }
} catch let error {
    print("Failed to initialize RTM client. Error: \(error)")
}
```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="mini-program" />
```javascript
// Handle message event
rtm.addEventListener("message", event => {
    const channelType = event.channelType;      // The channel type need to be "STREAM", "MESSAGE" or "USER".
    const channelName = event.channelName;      // The name of the channel that this message comes from.
    const topic = event.topicName;              // (Stream channel only) The name of the topic that this message comes from.
    const messageType = event.messageType;      // The message type need to be "STRING" or "BINARY".
    const customType = event.customType;        // User defined type.
    const publisher = event.publisher;          // Message publisher.
    const message = event.message;              // Message payload.
    const timestamp = event.timestamp;          // Event timestamp
});
// Handle presence event
rtm.addEventListener("presence", event => {
    const action = event.eventType;             // Which action it is ,should be one of 'SNAPSHOT'、'INTERVAL'、'JOIN'、'LEAVE'、'TIMEOUT、'STATE_CHANGED'、'OUT_OF_SERVICE'.
    const channelType = event.channelType;      // Which channel type it is, Should be "STREAM", "MESSAGE" or "USER".
    const channelName = event.channelName;      // Which channel does this event come from
    const publisher = event.publisher;          // Who trigger this event
    const states = event.stateChanged;          // User state payload, only for stateChanged event
    const interval = event.interval;            // Interval payload, only for interval event
    const snapshot = event.snapshot;            // Snapshot payload, only for snapshot event
    const timestamp = event.timestamp;          // Event timestamp
});
// Handle topic event
rtm.addEventListener("topic", event => {
    const action = event.evenType;              // Which action it is ,should be one of 'SNAPSHOT'、'JOIN'、'LEAVE'.
    const channelName = event.channelName;      // Which channel does this event come from
    const publisher = event.userId;             // Who trigger this event
    const topicInfos = event.topicInfos;        // Topic information payload
    const totalTopics = event.totalTopics;      // How many topics
    const timestamp = event.timestamp;          // Event timestamp
});
// Handle storage event
rtm.addEventListener("storage", event => {
    const channelType = event.channelType;      // Which channel type it is, Should be "STREAM", "MESSAGE" or "USER".
    const channelName = event.channelName;      // Which channel does this event come from
    const publisher = event.publisher;          // Who trigger this event
    const storageType = event.storageType;      // Which category the event is, should be 'USER'、'CHANNEL'
    const action = event.eventType;             // Which action it is ,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
rtm.addEventListener("lock", event => {
    const channelType = event.channelType;      // Which channel type it is, Should be "STREAM", "MESSAGE" or "USER".
    const channelName = event.channelName;      // Which channel does this event come from
    const publisher = event.publisher;          // Who trigger this event
    const action = event.evenType;              // Which action it is ,should be one of 'SET'、'REMOVED'、'ACQUIRED'、'RELEASED'、'EXPIRED'、'SNAPSHOT'
    const lockName = event.lockName;            // Which lock it effect
    const ttl = event.ttl;                      // The ttl of this lock
    const snapshot = event.snapshot;            // Snapshot payload
    const owner = event.owner;                  // The owner of this lock
    const timestamp = event.timestamp;          // Event timestamp
});
// Handle link state change event
rtm.addEventListener("linkState", event => {
    const currentState = event.currentState;          // Current link state
    const previousState = event.previousState;        // Previous link state
    const serviceType = event.serviceType;            // Service type
    const operation = event.operation;                // Operation that triggered this event
    const reason = event.reason;                      // Reason for the state change
    const affectedChannels = event.affectedChannels;  // Affected channels
    const timestamp = event.timestamp;                // Event timestamp
    const isResumed = event.isResumed;                // Whether the connection resumed
});
// Handle token privilege will expire event
rtm.addEventListener("tokenPrivilegeWillExpire", (channelName) => {
    const channelName = channelName;            // Which Channel Token Will Expire
});
```
<_PlatformProcessedMarker close="true" />
</_PlatformTabsGroup>

## 删除事件监听 [#删除事件监听]

<_PlatformTabsGroup>
<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="android" />
为避免内存泄漏、错误和异常（即空指针异常）引起的性能下降，声网建议你在不需要使用某个事件处理程序时对其进行注销。Java SDK 会在释放 `RtmClient` 时自动销毁事件处理程序。
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="ios" />
为避免内存泄漏、错误和异常（即空指针异常）引起的性能下降，声网建议你在不需要使用某个事件处理程序时对其进行注销。例如，如果不想关注 Lock 事件通知，删除对 `didReceiveLockEvent` 函数的定义即可。
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="web" />
为避免内存泄漏、错误和异常（即空指针异常）引起的性能下降，声网建议你在不需要使用某个事件处理程序时对其进行注销。如需注销事件监听程序，则需在添加事件监听时避免采用匿名函数的方式，以下是添加和注销事件监听程序的示例代码。

```javascript showLineNumbers
const messageReceived = (event) => {
    const channelType = event.channelType;      // Which channel type it is, Should be "STREAM", "MESSAGE" or "USER".
    const channelName = event.channelName;      // Which channel does this message come from
    const topic = event.topicName;              // Which Topic does this message come from, it is valid when the channelType is "STREAM".
    const messageType = event.messageType;      // Which message type it is, Should be "STRING" or "BINARY" .
    const customType = event.customType;        // User defined type
    const publisher = event.publisher;          // Message publisher
    const message = event.message;              // Message payload
    const timestamp = event.timestamp;          // Event timestamp
    // Your business processing logic program
};
// Add Event Listener
rtm.addEventListener("message", messageReceived);
// Remove Event Listener
rtm.removeEventListener("message", messageReceived);
```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="harmonyos" />
为避免内存泄漏、错误和异常（即空指针异常）引起的性能下降，声网建议你在不需要使用某个事件处理程序时对其进行注销。如需注销事件监听程序，则需在添加事件监听时避免采用匿名函数的方式，以下是添加和注销事件监听程序的示例代码。

```typescript
import { MessageEvent } from '@shengwang/rtm-full';

// Define message event handler function
const onMessageReceived = (event: object) => {
  const msgEvent = event as MessageEvent;
  console.log('Received message event:', msgEvent);
  // Your business logic
};

// Add event listener
rtmClient.addEventListener('message', onMessageReceived);

// Remove event listener
rtmClient.removeEventListener('message', onMessageReceived);
```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="unity" />
为避免内存泄漏、错误和异常（即空指针异常）引起的性能下降，声网建议你在不需要使用某个事件处理程序时对其进行注销。如需注销事件监听程序，则需在添加事件监听时避免采用匿名函数的方式，以下是添加和注销事件监听程序的示例代码。

```csharp
private void AddEventsListener()
{
    rtmClient.OnMessageEvent += OnMessageEvent;
    rtmClient.OnPresenceEvent += OnPresenceEvent;
    rtmClient.OnTopicEvent += OnTopicEvent;
    rtmClient.OnStorageEvent += OnStorageEvent;
    rtmClient.OnLockEvent += OnLockEvent;
    rtmClient.OnConnectionStateChanged += OnConnectionStateChanged;
    rtmClient.OnTokenPrivilegeWillExpire += OnTokenPrivilegeWillExpire;
}

private void RemoveEventsListener()
{
    rtmClient.OnMessageEvent -= OnMessageEvent;
    rtmClient.OnPresenceEvent -= OnPresenceEvent;
    rtmClient.OnTopicEvent -= OnTopicEvent;
    rtmClient.OnStorageEvent -= OnStorageEvent;
    rtmClient.OnLockEvent -= OnLockEvent;
    rtmClient.OnConnectionStateChanged -= OnConnectionStateChanged;
    rtmClient.OnTokenPrivilegeWillExpire -= OnTokenPrivilegeWillExpire;
}

private void OnMessageEvent( MessageEvent Event) { }

private void OnPresenceEvent( PresenceEvent Event) { }

private void OnTopicEvent( TopicEvent Event) { }
```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="flutter" />
为避免内存泄漏、错误和异常（即空指针异常）引起的性能下降，声网建议你在不需要使用某个事件处理程序时对其进行注销。如需注销事件监听程序，则需在添加事件监听时避免采用匿名函数的方式，以下是添加和注销事件监听程序的示例代码。

```dart
// 定义消息时间处理函数
void onMessageReceived(MessageEvent event) {
  print('Received message event: $event');
}
// 注册 message event
rtmClient.addListener(
  message: onMessageReceived
);
//移除 message event
rtmClient.removeListener(
    message: onMessageReceived
);
```
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="cpp" />
为避免内存泄漏、错误和异常（即空指针异常）引起的性能下降，声网建议你在不需要使用某个事件处理程序时对其进行注销。例如，如果不想关注 Lock 事件通知，删除对 `onLockEvent` 函数的定义即可。
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="swift" />
为避免内存泄漏、错误和异常（即空指针异常）引起的性能下降，声网建议你在不需要使用某个事件处理程序时对其进行注销。例如，如果不想关注 Lock 事件通知，删除对 `didReceiveLockEvent` 函数的定义即可。
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="mini-program" />
为避免内存泄漏、错误和异常（即空指针异常）引起的性能下降，声网建议你在不需要使用某个事件处理程序时对其进行注销。如需注销事件监听程序，则需在添加事件监听时避免采用匿名函数的方式，以下是添加和注销事件监听程序的示例代码。

```javascript showLineNumbers
const messageReceived = (event) => {
    const channelType = event.channelType;      // Which channel type it is, Should be "STREAM", "MESSAGE" or "USER".
    const channelName = event.channelName;      // Which channel does this message come from
    const topic = event.topicName;              // Which Topic does this message come from, it is valid when the channelType is "STREAM".
    const messageType = event.messageType;      // Which message type it is, Should be "STRING" or "BINARY" .
    const customType = event.customType;        // User defined type
    const publisher = event.publisher;          // Message publisher
    const message = event.message;              // Message payload
    const timestamp = event.timestamp;          // Event timestamp
    // Your business processing logic program
};
// Add Event Listener
rtm.addEventListener("message", messageReceived);
// Remove Event Listener
rtm.removeEventListener("message", messageReceived);
```
<_PlatformProcessedMarker close="true" />
</_PlatformTabsGroup>

## 事件通知类型 [#事件通知类型]

<_PlatformTabsGroup>
<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="android" />
RTM 一共有 7 种类型事件，对应的有 7 种事件监听程序。你可以查看 API 参考的[事件监听](/zh-CN/api-reference/rtm/android/configuration#事件监听)章节，了解每个事件监听程序传入参数的详细信息。

| 事件监听程序                                                     | 描述                                                                                                                                                                                                             |
| ------- | ----------------- |
| `onMessageEvent`    | 接收所有订阅的 Message Channel 中的消息通知或你加入的所有 Stream Channel 中订阅的 Topic 消息通知。事件负载数据中包含频道名称、频道类型、Topic 名称、事件发送者、消息负载数据类型等信息。                         |
| `onPresenceEvent`   | 接收所有订阅的 Message Channel 或者你加入的所有 Stream Channel 中远端用户的在线状态事件通知。事件负载数据中包含频道名称、频道类型、事件类型、事件发送者、用户临时状态数据等信息。                                |
| `onTopicEvent`      | 接收加入的所有 Stream Channel 中 Topic 变更事件通知。事件负载数据中包含频道名称、事件类型、Topic 名称、事件发送者（即 Topic 详情）等信息。                                                                       |
| `onStorageEvent`    | 接收订阅的 Message Channel 及加入的 Stream Channel 中所有的 Channel Metadata 事件通知，以及所有订阅用户的 User Metadata 事件通知。事件负载数据中包含频道名称、频道类型、事件类型（即具体 Metadata 数据）等信息。 |
| `onLockEvent`       | 接收订阅的 Message Channel 及加入的 Stream Channel 中所有的 Lock 事件通知。事件负载数据中包含有频道名称、频道类型、事件类型、锁详情等信息。                                                                      |
| `onLinkStateEvent`  | 接收客户端网络连接状态变更的事件通知，包含变更前后的连接状态、服务类型、导致变更的操作类型、变更原因、频道列表等信息。                                                                                           |
| `onTokenPrivilegeWillExpire` | 接收客户端 Token 将要过期的事件通知。                                                                                                                                                                            |
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="ios" />
RTM 一共有 7 种类型事件，对应的有 7 种事件监听程序。你可以查看 API 参考的[事件监听](/zh-CN/api-reference/rtm/ios/configuration#事件监听)章节，了解每个事件监听程序传入参数的详细信息。

| 事件监听程序                                                     | 描述                                                                                                                                                                                                             |
| ------- | ----------------- |
| `didReceiveMessageEvent`    | 接收所有订阅的 Message Channel 中的消息通知或你加入的所有 Stream Channel 中订阅的 Topic 消息通知。事件负载数据中包含频道名称、频道类型、Topic 名称、事件发送者、消息负载数据类型等信息。                         |
| `didReceivePresenceEvent`   | 接收所有订阅的 Message Channel 或者你加入的所有 Stream Channel 中远端用户的在线状态事件通知。事件负载数据中包含频道名称、频道类型、事件类型、事件发送者、用户临时状态数据等信息。                                |
| `didReceiveTopicEvent`      | 接收加入的所有 Stream Channel 中 Topic 变更事件通知。事件负载数据中包含频道名称、事件类型、Topic 名称、事件发送者（即 Topic 详情）等信息。                                                                       |
| `didReceiveStorageEvent`    | 接收订阅的 Message Channel 及加入的 Stream Channel 中所有的 Channel Metadata 事件通知，以及所有订阅用户的 User Metadata 事件通知。事件负载数据中包含频道名称、频道类型、事件类型（即具体 Metadata 数据）等信息。 |
| `didReceiveLockEvent`       | 接收订阅的 Message Channel 及加入的 Stream Channel 中所有的 Lock 事件通知。事件负载数据中包含有频道名称、频道类型、事件类型、锁详情等信息。                                                                      |
| `didReceiveLinkStateEvent`  | 接收客户端网络连接状态变更的事件通知，包含变更前后的连接状态、服务类型、导致变更的操作类型、变更原因、频道列表等信息。                                                                                           |
| `tokenPrivilegeWillExpire` | 接收客户端 Token 将要过期的事件通知。                                                                                                                                                                            |
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="web" />
RTM 一共有 7 种类型事件，对应的有 7 种事件监听程序。你可以查看 API 参考的[事件监听](/zh-CN/api-reference/rtm/web/configuration#事件监听)章节，了解每个事件监听程序传入参数的详细信息。

| 事件监听程序                                                     | 描述                                                                                                                                                                                                             |
| ------- | ----------------- |
| `message`    | 接收所有订阅的 Message Channel 中的消息通知或你加入的所有 Stream Channel 中订阅的 Topic 消息通知。事件负载数据中包含频道名称、频道类型、Topic 名称、事件发送者、消息负载数据类型等信息。                         |
| `presence`   | 接收所有订阅的 Message Channel 或者你加入的所有 Stream Channel 中远端用户的在线状态事件通知。事件负载数据中包含频道名称、频道类型、事件类型、事件发送者、用户临时状态数据等信息。                                |
| `topic`      | 接收加入的所有 Stream Channel 中 Topic 变更事件通知。事件负载数据中包含频道名称、事件类型、Topic 名称、事件发送者（即 Topic 详情）等信息。                                                                       |
| `storage`    | 接收订阅的 Message Channel 及加入的 Stream Channel 中所有的 Channel Metadata 事件通知，以及所有订阅用户的 User Metadata 事件通知。事件负载数据中包含频道名称、频道类型、事件类型（即具体 Metadata 数据）等信息。 |
| `lock`       | 接收订阅的 Message Channel 及加入的 Stream Channel 中所有的 Lock 事件通知。事件负载数据中包含有频道名称、频道类型、事件类型、锁详情等信息。                                                                      |
| `linkState`  | 接收客户端网络连接状态变更的事件通知，包含变更前后的连接状态、服务类型、导致变更的操作类型、变更原因、频道列表等信息。                                                                                           |
| `tokenPrivilegeWillExpire` | 接收客户端 Token 将要过期的事件通知。                                                                                                                                                                            |
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="harmonyos" />
RTM 一共有 7 种类型事件，对应的有 7 种事件监听程序。你可以查看 API 参考的[事件监听](/zh-CN/api-reference/rtm/harmonyos/configuration#事件监听)章节，了解每个事件监听程序传入参数的详细信息。

| 事件监听程序                                                     | 描述                                                                                                                                                                                                             |
| ------- | ----------------- |
| `message`    | 接收所有订阅的 Message Channel 中的消息通知或你加入的所有 Stream Channel 中订阅的 Topic 消息通知。事件负载数据中包含频道名称、频道类型、Topic 名称、事件发送者、消息负载数据类型等信息。                         |
| `presence`   | 接收所有订阅的 Message Channel 或者你加入的所有 Stream Channel 中远端用户的在线状态事件通知。事件负载数据中包含频道名称、频道类型、事件类型、事件发送者、用户临时状态数据等信息。                                |
| `topic`      | 接收加入的所有 Stream Channel 中 Topic 变更事件通知。事件负载数据中包含频道名称、事件类型、Topic 名称、事件发送者（即 Topic 详情）等信息。                                                                       |
| `storage`    | 接收订阅的 Message Channel 及加入的 Stream Channel 中所有的 Channel Metadata 事件通知，以及所有订阅用户的 User Metadata 事件通知。事件负载数据中包含频道名称、频道类型、事件类型（即具体 Metadata 数据）等信息。 |
| `lock`       | 接收订阅的 Message Channel 及加入的 Stream Channel 中所有的 Lock 事件通知。事件负载数据中包含有频道名称、频道类型、事件类型、锁详情等信息。                                                                      |
| `linkState`  | 接收客户端网络连接状态变更的事件通知，包含变更前后的连接状态、服务类型、导致变更的操作类型、变更原因、频道列表等信息。                                                                                           |
| `token` | 接收客户端 Token 将要过期的事件通知。                                                                                                                                                                            |
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="unity" />
RTM 一共有 7 种类型事件，对应的有 7 种事件监听程序。你可以查看 API 参考的[事件监听](/zh-CN/api-reference/rtm/unity/configuration#事件监听)章节，了解每个事件监听程序传入参数的详细信息。

| 事件监听程序                       | 描述                                                                                                                                                   |
|-----------|------ |
| `OnMessageEvent`                 | 接收所有订阅的 Message Channel 中的消息通知或你加入的所有 Stream Channel 中订阅的 Topic 消息通知。事件负载数据中包含频道名称、频道类型、Topic 名称、事件发送者、消息负载数据类型等信息。                                    |
| `OnPresenceEvent`                 | 接收所有订阅的 Message Channel 或者你加入的所有 Stream Channel 中远端用户的在线状态事件通知。事件负载数据中包含频道名称、频道类型、事件类型、事件发送者、用户临时状态数据等信息。 |
| `OnTopicEvent`                    | 接收加入的所有 Stream Channel 中 Topic 变更事件通知。事件负载数据中包含频道名称、事件类型、Topic 名称、事件发送者（即 Topic 详情）等信息。                                                                 |
| `OnStorageEvent`                  | 接收订阅的 Message Channel 及加入的 Stream Channel 中所有的 Channel Metadata 事件通知，以及所有订阅用户的 User Metadata 事件通知。事件负载数据中包含频道名称、频道类型、事件类型（即具体 Metadata 数据）等信息。        |
| `OnLockEvent`                     | 接收订阅的 Message Channel 及加入的 Stream Channel 中所有的 Lock 事件通知。事件负载数据中包含有频道名称、频道类型、事件类型、锁详情等信息。                                                      |
| `OnConnectionStateChanged`     | 接收客户端网络连接状态变更的事件通知，包含频道名称、连接状态以及变更原因等信息。                                                                                                        |
| `OnTokenPrivilegeWillExpire` | 接收客户端 Token 将要过期的事件通知。                                                                                                                            |
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="flutter" />
RTM 一共有 7 种类型事件，对应的有 7 种事件监听程序。你可以查看 API 参考的[事件监听](/zh-CN/api-reference/rtm/flutter/configuration#事件监听)章节，了解每个事件监听程序传入参数的详细信息。

| 事件监听程序                                                     | 描述                                                                                                                                                                                                             |
| ------- | ----------------- |
| `message`    | 接收所有订阅的 Message Channel 中的消息通知或你加入的所有 Stream Channel 中订阅的 Topic 消息通知。事件负载数据中包含频道名称、频道类型、Topic 名称、事件发送者、消息负载数据类型等信息。                         |
| `presence`   | 接收所有订阅的 Message Channel 或者你加入的所有 Stream Channel 中远端用户的在线状态事件通知。事件负载数据中包含频道名称、频道类型、事件类型、事件发送者、用户临时状态数据等信息。                                |
| `topic`      | 接收加入的所有 Stream Channel 中 Topic 变更事件通知。事件负载数据中包含频道名称、事件类型、Topic 名称、事件发送者（即 Topic 详情）等信息。                                                                       |
| `storage`    | 接收订阅的 Message Channel 及加入的 Stream Channel 中所有的 Channel Metadata 事件通知，以及所有订阅用户的 User Metadata 事件通知。事件负载数据中包含频道名称、频道类型、事件类型（即具体 Metadata 数据）等信息。 |
| `lock`       | 接收订阅的 Message Channel 及加入的 Stream Channel 中所有的 Lock 事件通知。事件负载数据中包含有频道名称、频道类型、事件类型、锁详情等信息。                                                                      |
| `linkState`  | 接收客户端网络连接状态变更的事件通知，包含变更前后的连接状态、服务类型、导致变更的操作类型、变更原因、频道列表等信息。                                                                                           |
| `token` | 接收客户端 Token 将要过期的事件通知。                                                                                                                                                                            |
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="cpp" />
RTM 一共有 7 种类型事件，对应的有 7 种事件监听程序。你可以查看 API 参考的[事件监听](/zh-CN/api-reference/rtm/cpp/configuration#事件监听)章节，了解每个事件监听程序传入参数的详细信息。

| 事件监听程序                                                     | 描述                                                                                                                                                                                                             |
| ------- | ----------------- |
| `onMessageEvent`    | 接收所有订阅的 Message Channel 中的消息通知或你加入的所有 Stream Channel 中订阅的 Topic 消息通知。事件负载数据中包含频道名称、频道类型、Topic 名称、事件发送者、消息负载数据类型等信息。                         |
| `onPresenceEvent`   | 接收所有订阅的 Message Channel 或者你加入的所有 Stream Channel 中远端用户的在线状态事件通知。事件负载数据中包含频道名称、频道类型、事件类型、事件发送者、用户临时状态数据等信息。                                |
| `onTopicEvent`      | 接收加入的所有 Stream Channel 中 Topic 变更事件通知。事件负载数据中包含频道名称、事件类型、Topic 名称、事件发送者（即 Topic 详情）等信息。                                                                       |
| `onStorageEvent`    | 接收订阅的 Message Channel 及加入的 Stream Channel 中所有的 Channel Metadata 事件通知，以及所有订阅用户的 User Metadata 事件通知。事件负载数据中包含频道名称、频道类型、事件类型（即具体 Metadata 数据）等信息。 |
| `onLockEvent`       | 接收订阅的 Message Channel 及加入的 Stream Channel 中所有的 Lock 事件通知。事件负载数据中包含有频道名称、频道类型、事件类型、锁详情等信息。                                                                      |
| `onLinkStateEvent`  | 接收客户端网络连接状态变更的事件通知，包含变更前后的连接状态、服务类型、导致变更的操作类型、变更原因、频道列表等信息。                                                                                           |
| `onTokenPrivilegeWillExpire` | 接收客户端 Token 将要过期的事件通知。                                                                                                                                                                            |
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="swift" />
RTM 一共有 7 种类型事件，对应的有 7 种事件监听程序。你可以查看 API 参考的[事件监听](/zh-CN/api-reference/rtm/swift/configuration#事件监听)章节，了解每个事件监听程序传入参数的详细信息。

| 事件监听程序                                                     | 描述                                                                                                                                                                                                             |
| ------- | ----------------- |
| `didReceiveMessageEvent`    | 接收所有订阅的 Message Channel 中的消息通知或你加入的所有 Stream Channel 中订阅的 Topic 消息通知。事件负载数据中包含频道名称、频道类型、Topic 名称、事件发送者、消息负载数据类型等信息。                         |
| `didReceivePresenceEvent`   | 接收所有订阅的 Message Channel 或者你加入的所有 Stream Channel 中远端用户的在线状态事件通知。事件负载数据中包含频道名称、频道类型、事件类型、事件发送者、用户临时状态数据等信息。                                |
| `didReceiveTopicEvent`      | 接收加入的所有 Stream Channel 中 Topic 变更事件通知。事件负载数据中包含频道名称、事件类型、Topic 名称、事件发送者（即 Topic 详情）等信息。                                                                       |
| `didReceiveStorageEvent`    | 接收订阅的 Message Channel 及加入的 Stream Channel 中所有的 Channel Metadata 事件通知，以及所有订阅用户的 User Metadata 事件通知。事件负载数据中包含频道名称、频道类型、事件类型（即具体 Metadata 数据）等信息。 |
| `didReceiveLockEvent`       | 接收订阅的 Message Channel 及加入的 Stream Channel 中所有的 Lock 事件通知。事件负载数据中包含有频道名称、频道类型、事件类型、锁详情等信息。                                                                      |
| `didReceiveLinkStateEvent`  | 接收客户端网络连接状态变更的事件通知，包含变更前后的连接状态、服务类型、导致变更的操作类型、变更原因、频道列表等信息。                                                                                           |
| `tokenPrivilegeWillExpire` | 接收客户端 Token 将要过期的事件通知。                                                                                                                                                                            |
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="mini-program" />
RTM 一共有 7 种类型事件，对应的有 7 种事件监听程序。你可以查看 API 参考的[事件监听](/zh-CN/api-reference/rtm/web/configuration#事件监听)章节，了解每个事件监听程序传入参数的详细信息。

| 事件监听程序                                                     | 描述                                                                                                                                                                                                             |
| ------- | ----------------- |
| `message`    | 接收所有订阅的 Message Channel 中的消息通知或你加入的所有 Stream Channel 中订阅的 Topic 消息通知。事件负载数据中包含频道名称、频道类型、Topic 名称、事件发送者、消息负载数据类型等信息。                         |
| `presence`   | 接收所有订阅的 Message Channel 或者你加入的所有 Stream Channel 中远端用户的在线状态事件通知。事件负载数据中包含频道名称、频道类型、事件类型、事件发送者、用户临时状态数据等信息。                                |
| `topic`      | 接收加入的所有 Stream Channel 中 Topic 变更事件通知。事件负载数据中包含频道名称、事件类型、Topic 名称、事件发送者（即 Topic 详情）等信息。                                                                       |
| `storage`    | 接收订阅的 Message Channel 及加入的 Stream Channel 中所有的 Channel Metadata 事件通知，以及所有订阅用户的 User Metadata 事件通知。事件负载数据中包含频道名称、频道类型、事件类型（即具体 Metadata 数据）等信息。 |
| `lock`       | 接收订阅的 Message Channel 及加入的 Stream Channel 中所有的 Lock 事件通知。事件负载数据中包含有频道名称、频道类型、事件类型、锁详情等信息。                                                                      |
| `linkState`  | 接收客户端网络连接状态变更的事件通知，包含变更前后的连接状态、服务类型、导致变更的操作类型、变更原因、频道列表等信息。                                                                                           |
| `tokenPrivilegeWillExpire` | 接收客户端 Token 将要过期的事件通知。                                                                                                                                                                            |
<_PlatformProcessedMarker close="true" />
</_PlatformTabsGroup>

完成事件监听处理程序后，你可以通过订阅频道或 Topic 来接收指定的 Message Channel 或 Stream Channel 中的消息和事件通知了。详见[订阅 Message Channel](/zh-CN/realtime-media/rtm/build/channels-and-topics/message-channel#订阅频道) 和[订阅 Topic](/zh-CN/realtime-media/rtm/build/channels-and-topics/topics/usage#订阅-topic)。
