Event overview
Configure OpenIM Flutter SDK listeners centrally and dispatch events by business domain.
The OpenIM Flutter SDK uses listeners to deliver connection, synchronization, user, relationship, conversation, conversation-group, group, message, and call changes. Each manager retains only one corresponding listener, and a later configuration replaces the Dart instance stored previously. Compose every callback when initializing the application state layer, and configure each listener type exactly once. Do not configure listeners in a widget's build() method or separately on each feature screen.
Configure listeners centrally
The following example shows an application-level composition entry point. The complete merge logic for each handle* function belongs on the ownership page linked in the table below.
Future<void> registerOpenIMListeners() async {
await OpenIM.iMManager.userManager.setUserListener(
OnUserListener(
onSelfInfoUpdated: handleSelfInfoUpdated,
onUserStatusChanged: handleUserStatusChanged,
),
);
await OpenIM.iMManager.friendshipManager.setFriendshipListener(
OnFriendshipListener(
onBlackAdded: handleBlackAdded,
onBlackDeleted: handleBlackDeleted,
onFriendAdded: handleFriendChanged,
onFriendDeleted: handleFriendDeleted,
onFriendInfoChanged: handleFriendChanged,
onFriendApplicationAdded: handleFriendApplicationChanged,
onFriendApplicationAccepted: handleFriendApplicationChanged,
onFriendApplicationRejected: handleFriendApplicationChanged,
onFriendApplicationDeleted: handleFriendApplicationDeleted,
),
);
await OpenIM.iMManager.conversationManager.setConversationListener(
OnConversationListener(
onNewConversation: handleNewConversations,
onConversationChanged: handleConversationsChanged,
onTotalUnreadMessageCountChanged: handleTotalUnreadChanged,
onInputStatusChanged: handleInputStatusChanged,
onSyncServerStart: handleSyncStart,
onSyncServerProgress: handleSyncProgress,
onSyncServerFinish: handleSyncFinish,
onSyncServerFailed: handleSyncFailed,
),
);
await OpenIM.iMManager.groupManager.setGroupListener(
OnGroupListener(
onJoinedGroupAdded: handleJoinedGroupAdded,
onJoinedGroupDeleted: handleJoinedGroupDeleted,
onGroupInfoChanged: handleGroupInfoChanged,
onGroupDismissed: handleGroupDismissed,
onGroupMemberAdded: handleGroupMemberAdded,
onGroupMemberDeleted: handleGroupMemberDeleted,
onGroupMemberInfoChanged: handleGroupMemberInfoChanged,
onGroupApplicationAdded: handleGroupApplicationChanged,
onGroupApplicationAccepted: handleGroupApplicationChanged,
onGroupApplicationRejected: handleGroupApplicationChanged,
onGroupApplicationDeleted: handleGroupApplicationDeleted,
),
);
await OpenIM.iMManager.messageManager.setAdvancedMsgListener(
OnAdvancedMsgListener(
onRecvNewMessage: handleNewMessage,
onRecvOfflineNewMessage: handleOfflineMessage,
onRecvOnlineOnlyMessage: handleOnlineOnlyMessage,
onMsgDeleted: handleMessageDeleted,
onNewRecvMessageRevoked: handleMessageRevoked,
onRecvC2CReadReceipt: handleC2CReadReceipts,
onMessageModified: handleMessageModified,
onChangedPinnedMsg: handlePinnedMessagesChanged,
),
);
await OpenIM.iMManager.messageManager.setCustomBusinessListener(
OnCustomBusinessListener(
onRecvCustomBusinessMessage: handleCustomBusinessMessage,
),
);
await OpenIM.iMManager.signalingManager.setSignalingListener(
OnSignalingListener(
onReceiveNewInvitation: handleIncomingCall,
onInviteeAccepted: handleInviteeAccepted,
onInviteeRejected: handleInviteeRejected,
onInvitationCancelled: handleInvitationCancelled,
onInvitationTimeout: handleInvitationTimeout,
onInviteeAcceptedByOtherDevice: handleAcceptedElsewhere,
onInviteeRejectedByOtherDevice: handleRejectedElsewhere,
onHangup: handleHangup,
onRoomParticipantConnected: handleParticipantConnected,
onRoomParticipantDisconnected: handleParticipantDisconnected,
onStreamChange: handleStreamChange,
onReceiveCustomSignal: handleCustomSignal,
),
);
}ConversationGroupManager retains the conversation-group listener separately, so it is not configured again in this combined entry point. See Conversation groups overview for its complete registration, five callback types, and state-merging rules.
The pinned SDK does not expose corresponding remove or unset APIs. On sign-out, account switch, or state-layer disposal, stop dispatching callbacks to the old account and disposed widgets, and release the application's own references. After signing in again, overwrite the configurations with the complete listener set for the new account.
Event ownership
| Event scope | Merge identifier | Complete handling page |
|---|---|---|
| User profile and online status | userID | User overview |
| Friends and blocklist | userID | Retrieve the friend list by page |
| Conversation list | conversationID | Retrieve the conversation list |
| Conversation groups | conversationGroupID | Conversation groups overview |
| Total unread count | Current signed-in user | Maintain the total unread count |
| Typing status | conversationID:userID | Report typing status |
| Groups | groupID | Group overview |
| Group members | groupID:userID | Group-member retrieval |
| Group applications | groupID:userID | Group applications overview |
| New messages | conversationID:clientMsgID | Receive messages |
| Message deletion | conversationID:clientMsgID | Delete a message |
| Message recall | conversationID:clientMsgID | Recall a message |
| Message modification | conversationID:clientMsgID | Modify a message |
| Pinned messages | conversationID; messages by clientMsgID | Pin or unpin a message |
| One-to-one read receipts | conversationID:clientMsgID | Mark a conversation as read |
| Custom business notifications | ID or idempotency key from the business protocol | Receive custom business messages |
| Calls | roomID; participants also use user IDs | Call events |
| Custom call signals | roomID:eventID | Send a custom signal |
Listen for initial synchronization
The synchronization lifecycle also belongs to the application's single OnConversationListener. It describes SDK data synchronization and is not the Future callback of any query API.
void handleSyncStart(bool? reinstalled) {
setSyncState(status: 'syncing', progress: 0, reinstalled: reinstalled == true);
}
void handleSyncProgress(int? progress) {
setSyncState(status: 'syncing', progress: progress ?? 0);
}
void handleSyncFinish(bool? reinstalled) {
setSyncState(status: 'ready', progress: 100, reinstalled: reinstalled == true);
reloadVisibleSnapshots();
}
void handleSyncFailed(bool? reinstalled) {
setSyncState(status: 'failed', reinstalled: reinstalled == true);
}Use onSyncServerStart to enter the synchronizing state and onSyncServerProgress to update progress. After completion, re-query the snapshots required by the current UI. On failure, record the error and wait for retry or connection recovery. Always treat event increments, query snapshots, and Future completion as separate stages.
Was this page helpful?