# Thread messages (/en/realtime-media/im/build/build-groups-rooms-and-threads/threading/thread-messages/android)

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

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.

    ## Understand the tech [#understand-the-tech]

    The Chat SDK provides the `ChatManager`, `ChatMessage`, and `ChatThread` classes for thread messages, which allows you to implement the following features:

    ## Prerequisites [#prerequisites]

    Before proceeding, ensure that you meet the following requirements:

    * You have initialized the Chat SDK. For details, see [SDK quickstart](../../../get-started-sdk).
    * You understand the call frequency limit of the Chat APIs supported by different pricing plans as described in [Limitations](../../limitations).

    <CalloutContainer type="info">
      <CalloutDescription>
        The thread feature is supported by all types of [Pricing Plans](../../../reference/pricing-plan-details) and is enabled by default once you have enabled Chat in [Agora Console](https://console.agora.io/v2).
      </CalloutDescription>
    </CalloutContainer>

    ## Implementation [#implementation]

    This section describes how to call the APIs provided by the Chat SDK to implement thread features.

    ### Send a thread message [#send-a-thread-message]

    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:

    ```java
    // Calls `createTxtSendMessage` to create a text message.
    // Sets `content` to the content of the text message.
    // Sets `chatThreadId` to the thread ID.
    ChatMessage message = ChatMessage.createTxtSendMessage(content, chatThreadId);
    // Sets `ChatType` to `GroupChat` as a thread belongs to a chat group.
    message.setChatType(ChatType.GroupChat);
    // Sets `isChatThreadMessage` to `true` to mark this message as a thread message.
    message.setIsChatThreadMessage(true);
    // 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.
    message.setMessageStatusCallback(new CallBack() {
         @Override
         public void onSuccess() {
            showToast("The message is successfully sent");
         }
         @Override
         public void onError(int code, String error) {
             showToast("Failed to send the message");
         }
         @Override
         public void onProgress(int progress, String status) {
         }
    });
    // Calls `sendMessage` to send the text message.
    ChatClient.getInstance().chatManager().sendMessage(message);
    ```

    For more information about sending a message, see [Send Messages](../../build-core-messaging/messages/send-receive-messages#send-a-text-message).

    ### Receive a thread message [#receive-a-thread-message]

    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:

    ```java
    MessageListener msgListener = new MessageListener() {
       // The SDK triggers the `onMessageReceived` callback when it receives a message.
       // After receiving this callback, the SDK parses the message and displays it.
       @Override
       public void onMessageReceived(List messages) {
           for (ChatMessage message : messages) {
               if(message.isChatThreadMessage()) {
                   // You can implement subsequent settings in this callback.
               }
           }
       }
       ...
    };
    // Calls `addMessageListener` to add a message listener.
    ChatClient.getInstance().chatManager().addMessageListener(msgListener);
    // Calls `removeMessageListener` to remove the message listener.
    ChatClient.getInstance().chatManager().removeMessageListener(msgListener);
    ```

    For more information about receiving a message, see [Receive Messages](../../build-core-messaging/messages/send-receive-messages#receive-a-message).

    ### Recall a thread message [#recall-a-thread-message]

    For details about how to recall a message, refer to [Recall Messages](../../build-core-messaging/messages/send-receive-messages#recall-a-message).

    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:

    ```java
    MessageListener msgListener = new MessageListener() {
       // The SDK triggers the `onMessageRecalled` callback when it recalls a message.
       // After receiving this callback, the SDK parses the message and updates its display.
       @Override
       public void onMessageRecalled(List messages) {
           for (ChatMessage message : messages) {
               if(message.isChatThreadMessage()) {
                   // You can implement subsequent settings in this callback.
               }
           }
       }
       ...
    };
    ```

    ### Retrieve thread messages [#retrieve-thread-messages]

    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.

    #### Retrieve messages of a thread from the server [#retrieve-messages-of-a-thread-from-the-server]

    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.

    ```java
    String chatThreadId = "{your chatThreadId}";
    Conversation.ConversationType type = Conversation.ConversationType.GroupChat;
    int pageSize = 10;
    String 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.
    Conversation.SearchDirection direction = Conversation.SearchDirection.DOWN;

    ChatClient.getInstance().chatManager().asyncFetchHistoryMessage(chatThreadId, type,
            pageSize, startMsgId, direction, new ValueCallBack>() {
        @Override
        public void onSuccess(CursorResult value) {

        }

        @Override
        public void onError(int error, String errorMsg) {

        }
    });
    ```

    #### Retrieve messages of a thread locally [#retrieve-messages-of-a-thread-locally]

    By calling [`loadAllConversations`](../../build-core-messaging/messages/manage-messages#retrieve-conversations), 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:

    ```java
    // Sets the conversation type to group chat as a thread belongs to a chat group.
    // Sets `isChatThread` to `true` to mark the conversation as a thread.
    ChatConversation conversation = ChatClient.getInstance().chatManager().getConversation(chatThreadId, ChatConversationType.GroupChat, createIfNotExists, isChatThread);
    // Retrieves messages in the specified thread from the local database. The SDK automatically loads and stores the retrieved messages to the memory.
    List messages = conversation.loadMoreMsgFromDB(startMsgId, pagesize, searchDirection);
    ```

    
  
      
  
      
  
      
  
      
  
      
  
      
  
