> ## Documentation Index
> Fetch the complete documentation index at: https://cometchat-22654f5b-docs-rn-guide-message-privately.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Threaded Messages

> Send, receive, and fetch threaded messages in conversations using the CometChat Android SDK.

<Accordion title="AI Integration Quick Reference">
  <Tabs>
    <Tab title="Kotlin">
      ```kotlin theme={null}
      // Send message in thread
      val textMessage = TextMessage("UID", "Reply text", CometChatConstants.RECEIVER_TYPE_USER)
      textMessage.parentMessageId = 100
      CometChat.sendMessage(textMessage, object : CallbackListener<TextMessage>() {
          override fun onSuccess(message: TextMessage) { }
          override fun onError(e: CometChatException) { }
      })

      // Fetch thread messages
      val messagesRequest = MessagesRequest.MessagesRequestBuilder()
          .setParentMessageId(100)
          .setLimit(30)
          .build()
      messagesRequest.fetchPrevious(callback)

      // Exclude threads from main conversation
      val messagesRequest = MessagesRequest.MessagesRequestBuilder()
          .setUID("user_uid")
          .hideReplies(true)
          .build()
      ```
    </Tab>

    <Tab title="Java">
      ```java theme={null}
      // Send message in thread
      TextMessage textMessage = new TextMessage("UID", "Reply text", CometChatConstants.RECEIVER_TYPE_USER);
      textMessage.setParentMessageId(100);
      CometChat.sendMessage(textMessage, new CallbackListener<TextMessage>() {
          @Override
          public void onSuccess(TextMessage message) { }
          @Override
          public void onError(CometChatException e) { }
      });

      // Fetch thread messages
      MessagesRequest messagesRequest = new MessagesRequest.MessagesRequestBuilder()
          .setParentMessageId(100)
          .setLimit(30)
          .build();
      messagesRequest.fetchPrevious(callback);

      // Exclude threads from main conversation
      MessagesRequest messagesRequest = new MessagesRequest.MessagesRequestBuilder()
          .setUID("user_uid")
          .hideReplies(true)
          .build();
      ```
    </Tab>
  </Tabs>
</Accordion>

Messages that are started from a particular message are called Threaded messages or simply threads. Each Thread is attached to a message which is the Parent message for that thread.

## Send Message in a Thread

Any message type ([`TextMessage`](/sdk/reference/messages#textmessage), [`MediaMessage`](/sdk/reference/messages#mediamessage), or [`CustomMessage`](/sdk/reference/messages#custommessage)) can be sent in a thread. Set the `parentMessageId` using `setParentMessageId()` to indicate which thread the message belongs to.

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    TextMessage textMessage = new TextMessage(UID, "Hello", CometChatConstants.RECEIVER_TYPE_USER);
    textMessage.setParentMessageId(100);

    CometChat.sendMessage(textMessage, new CometChat.CallbackListener<TextMessage>() {
      @Override
        public void onSuccess(TextMessage textMessage) {
        Log.d(TAG, "Text Message Sent successfully");
      }

      @Override
        public void onError(CometChatException e) {
        Log.d(TAG, "Text Message Failed : " + e.getMessage());
      }
    }); 
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    val textMessage = TextMessage(UID, "Hello", CometChatConstants.RECEIVER_TYPE_USER)
    textMessage.parentMessageId = 100

    CometChat.sendMessage(textMessage, object : CallbackListener<TextMessage?>() {
      override fun onSuccess(textMessage: TextMessage?) {
        Log.d(TAG, "Text Message Sent successfully")
      }

      override fun onError(e: CometChatException) {
        Log.d(TAG, "Text Message Failed : " + e.message)
      }
    })
    ```
  </Tab>
</Tabs>

Media and Custom messages can also be sent in threads using `setParentMessageId()`.

### Receiving Real-Time Messages

Use `MessageListener` to receive real-time thread messages. Check if the received message belongs to the active thread using `getParentMessageId()`.

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    private String listenerID = "UNIQUE_LISTENER_ID";
    private int activeThreadId = 100;

    CometChat.addMessageListener(listenerID, new CometChat.MessageListener() {
      @Override
      public void onTextMessageReceived(TextMessage textMessage) {
        if(message.getParentMessageId() == activeThreadId) {
          Log.d(TAG,"Text Message Received for active thread");
        }
      }

      @Override
      public void onMediaMessageReceived(MediaMessage mediaMessage) {
        if(message.getParentMessageId() == activeThreadId) {
          Log.d(TAG,"Media Message Received for active thread");
        }
      }

      @Override
        public void onCustomMessageReceived(CustomMessage customMessage) {
        if(message.getParentMessageId() == activeThreadId) {
            Log.d(TAG,"Custome Message Received for active thread");
        }
      }
    });
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    val listenerID = "UNIQUE_LISTENER_ID"
    val activeThreadId = 100

    CometChat.addMessageListener(listenerID, object : MessageListener() {
        override fun onTextMessageReceived(textMessage: TextMessage) {
            if (message!!.parentMessageId === activeThreadId) {
                Log.d(TAG, "Text Message Received for active thread")
            }
        }

        override fun onMediaMessageReceived(mediaMessage: MediaMessage) {
            if (message!!.parentMessageId === activeThreadId) {
                Log.d(TAG, "Media Message Received for active thread")
            }
        }

        override fun onCustomMessageReceived(customMessage: CustomMessage) {
            if (message!!.parentMessageId === activeThreadId) {
                Log.d(TAG, "Custome Message Received for active thread")
            }
        }
    })
    ```
  </Tab>
</Tabs>

### Fetch Thread Messages

Use `MessagesRequestBuilder` with `setParentMessageId()` to fetch messages belonging to a specific thread. Call `fetchPrevious()` to get messages (max 100 per request).

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    MessagesRequest messagesRequest = neMessagesRequest.MessagesRequestBuilder()
      .setLimit(30)
      .setParentMessageId(100)
      .build();
          
    messagesRequest.fetchPrevious(new CometChat.CallbackListener<List<BaseMessage>>() {
      @Override
        public void onSuccess(List<BaseMessage> messages) {
        Log.d(TAG, "Messages for thread fetched successfully");        
      }

      @Override
        public void onError(CometChatException e) {
        Log.d(TAG, "Message Fetching failed : "+ e.getMessage());
      }
    });
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    val messagesRequest: MessagesRequest = neMessagesRequest.MessagesRequestBuilder()
      .setLimit(30)
      .setParentMessageId(100)
      .build()

    messagesRequest.fetchPrevious(object : CallbackListener<List<BaseMessage?>?>() {
      override fun onSuccess(messages: List<BaseMessage?>?) {
        Log.d(TAG, "Messages for thread fetched successfully")
      }

      override fun onError(e: CometChatException) {
        Log.d(TAG, "Message Fetching failed : " + e.message)
      }
    })
    ```
  </Tab>
</Tabs>

## Avoid Threaded Messages in User/Group Conversations

Use `hideReplies(true)` to exclude threaded messages when fetching messages for a conversation.

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    MessagesRequest messagesRequest = neMessagesRequest.MessagesRequestBuilder()
      .setLimit(30)
      .setUID("cometchat-uid-1")
      .hideReplies(true)
      .build();
          
    messagesRequest.fetchPrevious(new CometChat.CallbackListener<List<BaseMessage>>() {
      @Override
        public void onSuccess(List<BaseMessage> messages) {
        Log.d(TAG, "Messages for thread fetched successfully");        
      }

      @Override
        public void onError(CometChatException e) {
        Log.d(TAG, "Message Fetching failed : "+ e.getMessage());
      }
    });
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    val messagesRequest: MessagesRequest = neMessagesRequest.MessagesRequestBuilder()
      .setLimit(30)
      .setUID("cometchat-uid-1")
      .hideReplies(true)
      .build()

    messagesRequest.fetchPrevious(object : CallbackListener<List<BaseMessage?>?>() {
      override fun onSuccess(messages: List<BaseMessage?>?) {
        Log.d(TAG, "Messages for thread fetched successfully")
      }

      override fun onError(e: CometChatException) {
        Log.d(TAG, "Message Fetching failed : " + e.message)
      }
    }) 
    ```
  </Tab>
</Tabs>

The above snippet will return messages between the logged in user and `cometchat-uid-1` excluding all the threaded messages belonging to the same conversation.

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Send Messages" icon="paper-plane" href="/sdk/android/send-message">
    Learn how to send text, media, and custom messages
  </Card>

  <Card title="Receive Messages" icon="envelope" href="/sdk/android/receive-messages">
    Handle real-time message events with listeners
  </Card>

  <Card title="Message Structure" icon="list" href="/sdk/android/message-structure-and-hierarchy">
    Understand message objects and their properties
  </Card>

  <Card title="Reactions" icon="heart" href="/sdk/android/reactions">
    Add emoji reactions to messages
  </Card>
</CardGroup>
