Threads enable users to create a separate conversation from a specific message within a chat group to keep the main chat uncluttered.
This page shows how to use the Chat SDK to send, receive, recall, and retrieve thread messages in your app.
The Chat SDK provides the ChatManager
, ChatMessage
, and ChatThread
classes for thread messages, which allows you to implement the following features:
- Send a thread message
- Receive a thread message
- Recall a thread message
- Retrieve thread messages
The following figure shows the workflow of how clients send and receive peer-to-peer messages.
As shown in the figure, the workflow of peer-to-peer messaging is as follows:
- Clients retrieve a token from your app server.
- Client A and Client B log in to Chat.
- Client A sends a message to Client B. The message is sent to the Chat server and the server delivers the message to Client B. When Client B receives the message, the SDK triggers an event. Client B listens for the event and gets the message.
Before proceeding, ensure that you meet the following requirements:
- You have initialized the Chat SDK. For details, see SDK quickstart.
- You understand the call frequency limit of the Chat APIs supported by different pricing plans as described in Limitations.
The thread feature is supported by all types of
Pricing Plans and is enabled by default once you have enabled Chat in
Agora Console.
This section describes how to call the APIs provided by the Chat SDK to implement thread features.
Sending a thread message is similar to sending a message in a chat group. The difference lies in the isChatThreadMessage
field, as shown in the following code sample:
_25// Calls `createTxtSendMessage` to create a text message.
_25// Sets `content` to the content of the text message.
_25// Sets `chatThreadId` to the thread ID.
_25ChatMessage message = ChatMessage.createTxtSendMessage(content, chatThreadId);
_25// Sets `ChatType` to `GroupChat` as a thread belongs to a chat group.
_25message.setChatType(ChatType.GroupChat);
_25// Sets `isChatThreadMessage` to `true` to mark this message as a thread message.
_25message.setIsChatThreadMessage(true);
_25// Calls `setMessageStatusCallback` to listen for the message sending status. You can implement subsequent settings in this callback, for example, displaying a pop-up if the message sending fails.
_25message.setMessageStatusCallback(new CallBack() {
_25 public void onSuccess() {
_25 showToast("The message is successfully sent");
_25 public void onError(int code, String error) {
_25 showToast("Failed to send the message");
_25 public void onProgress(int progress, String status) {
_25// Calls `sendMessage` to send the text message.
_25ChatClient.getInstance().chatManager().sendMessage(message);
For more information about sending a message, see Send Messages.
Once a thread has a new message, all chat group members receive the ChatThreadChangeListener#onChatThreadUpdated
callback. Thread members can also listen for the MessageListener#onMessageReceived
callback to receive thread messages, as shown in the following code sample:
_17MessageListener msgListener = new MessageListener() {
_17 // The SDK triggers the `onMessageReceived` callback when it receives a message.
_17 // After receiving this callback, the SDK parses the message and displays it.
_17 public void onMessageReceived(List<ChatMessage> messages) {
_17 for (ChatMessage message : messages) {
_17 if(message.isChatThreadMessage()) {
_17 // You can implement subsequent settings in this callback.
_17// Calls `addMessageListener` to add a message listener.
_17ChatClient.getInstance().chatManager().addMessageListener(msgListener);
_17// Calls `removeMessageListener` to remove the message listener.
_17ChatClient.getInstance().chatManager().removeMessageListener(msgListener);
For more information about receiving a message, see Receive Messages.
For details about how to recall a message, refer to Recall Messages.
Once a message is recalled in a thread, all chat group members receive the ChatThreadChangeListener#onChatThreadUpdated
callback. Thread members can also listen for the MessageListener#onMessageRecalled
callback, as shown in the following code sample:
_13MessageListener msgListener = new MessageListener() {
_13 // The SDK triggers the `onMessageRecalled` callback when it recalls a message.
_13 // After receiving this callback, the SDK parses the message and updates its display.
_13 public void onMessageRecalled(List<ChatMessage> messages) {
_13 for (ChatMessage message : messages) {
_13 if(message.isChatThreadMessage()) {
_13 // You can implement subsequent settings in this callback.
You can retrieve thread messages locally or from the server, depending on your production environment.
You can check ChatConversation#isChatThread()
to determine whether the current conversation is a thread conversation.
You can call asyncFetchHistoryMessage
to retrieve messages of a thread from the server. The only difference between retrieving messages of a thread from the server and retrieving group messages is that a thread ID needs to be passed in for the former and a group ID is required for the latter.
_18String chatThreadId = "{your chatThreadId}";
_18Conversation.ConversationType type = Conversation.ConversationType.GroupChat;
_18String startMsgId = "";// Starting message ID for retrieving. If you pass in an empty string, the SDK will retrieve messages according to the search direction while ignoring this parameter.
_18Conversation.SearchDirection direction = Conversation.SearchDirection.DOWN;
_18ChatClient.getInstance().chatManager().asyncFetchHistoryMessage(chatThreadId, type,
_18 pageSize, startMsgId, direction, new ValueCallBack<CursorResult<ChatMessage>>() {
_18 public void onSuccess(CursorResult<ChatMessage> value) {
_18 public void onError(int error, String errorMsg) {
By calling loadAllConversations
, you can only retrieve local one-to-one chat conversations and group conversations. To retrieve messages of a thread locally, refer to the following code sample:
_5// Sets the conversation type to group chat as a thread belongs to a chat group.
_5// Sets `isChatThread` to `true` to mark the conversation as a thread.
_5ChatConversation conversation = ChatClient.getInstance().chatManager().getConversation(chatThreadId, ChatConversationType.GroupChat, createIfNotExists, isChatThread);
_5// Retrieves messages in the specified thread from the local database. The SDK automatically loads and stores the retrieved messages to the memory.
_5List<ChatMessage> messages = conversation.loadMoreMsgFromDB(startMsgId, pagesize, searchDirection);