Documentation Index Fetch the complete documentation index at: https://cometchat-22654f5b-docs-android-v6-beta2.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
AI Integration Quick Reference
Field Value Package com.cometchat:chat-uikit-androidKey components CometChatThreadHeader, CometChatMessageList, CometChatMessageComposerPurpose Implement threaded replies so users can respond to specific messages in a focused sub-conversation. Related Threaded Messages Header , Message List , Message Composer , All Guides
Implement threaded replies in your Android chat app using CometChat’s UI Kit, enabling users to reply to specific messages in a focused sub-conversation.
Overview
Threaded replies allow users to respond directly to a specific message in one-on-one or group chats, improving context and readability:
Organizes related replies into a dedicated thread view.
Mirrors functionality in Slack, Discord, and WhatsApp.
Maintains clarity in active conversations.
Users tap a message → open thread screen → view parent message + replies → compose within thread.
Prerequisites
Android project in Android Studio.
CometChat Android UI Kit v5 added to your build.gradle.
Valid CometChat App ID , Auth Key , and Region initialized.
<uses-permission android:name="android.permission.INTERNET"/> in AndroidManifest.xml.
Logged-in user via CometChat.login().
Existing MessagesActivity using CometChatMessageList.
Components
Component Role activity_thread_message.xmlDefines thread UI: header, message list, composer, unblock. ThreadMessageActivityHosts thread screen; initializes UI & ViewModel. ThreadMessageViewModelFetches parent message & thread replies; manages state. CometChatMessageListDisplays threaded replies when given parent message ID. CometChatMessageComposerComposes and sends replies with parentMessageId. CometChatMessageOptionDefines “Message Privately” in message context menus. UserDetailActivityHandles blocked-user UI; hides composer & shows unblock.
Integration Steps
Step 1: Add Thread Layout
Create res/layout/activity_thread_message.xml:
activity_thread_message.xml
<? xml version = "1.0" encoding = "utf-8" ?>
< LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android"
android:layout_width = "match_parent"
android:layout_height = "match_parent"
android:orientation = "vertical" >
< com.cometchat.chatuikit.threadheader.CometChatThreadHeader
android:id = "@+id/threadHeader"
android:layout_width = "match_parent"
android:layout_height = "wrap_content" />
< com.cometchat.chatuikit.messagelist.CometChatMessageList
android:id = "@+id/threadMessageList"
android:layout_width = "match_parent"
android:layout_height = "0dp"
android:layout_weight = "1" />
< LinearLayout
android:id = "@+id/unblockLayout"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:gravity = "center"
android:padding = "12dp"
android:visibility = "gone" >
< Button
android:id = "@+id/unblockBtn"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:text = "Unblock" />
</ LinearLayout >
< com.cometchat.chatuikit.messagecomposer.CometChatMessageComposer
android:id = "@+id/threadComposer"
android:layout_width = "match_parent"
android:layout_height = "wrap_content" />
</ LinearLayout >
File reference:
activity_thread_message.xml
Step 2: Set up ThreadMessageActivity
Initialize UI & handle blocked-user flows:
class ThreadMessageActivity : AppCompatActivity () {
override fun onCreate (savedInstanceState: Bundle ?) {
super . onCreate (savedInstanceState)
setContentView (R.layout.activity_thread_message)
val header = findViewById < CometChatThreadHeader >(R.id.threadHeader)
val messageList = findViewById < CometChatMessageList >(R.id.threadMessageList)
val composer = findViewById < CometChatMessageComposer >(R.id.threadComposer)
val unblock = findViewById < View >(R.id.unblockLayout)
val rawMessage = intent. getStringExtra ( "raw_json" )
val viewModel = ViewModelProvider ( this )[ThreadMessageViewModel:: class .java]
if (rawMessage != null ) {
val parentMessage = BaseMessage. processMessage ( JSONObject (rawMessage))
viewModel. setParentMessage (parentMessage)
}
viewModel.parentMessage. observe ( this ) { msg ->
header. setParentMessage (msg)
messageList. setParentMessage (msg.id)
composer. setParentMessageId (msg.id)
}
// Handle blocked user
if (isBlockedByMe) {
composer.visibility = View.GONE
unblock.visibility = View.VISIBLE
}
}
}
public class ThreadMessageActivity extends AppCompatActivity {
@ Override
protected void onCreate ( Bundle savedInstanceState ) {
super . onCreate (savedInstanceState);
setContentView ( R . layout . activity_thread_message );
CometChatThreadHeader header = findViewById ( R . id . threadHeader );
CometChatMessageList messageList = findViewById ( R . id . threadMessageList );
CometChatMessageComposer composer = findViewById ( R . id . threadComposer );
View unblock = findViewById ( R . id . unblockLayout );
String rawMessage = getIntent (). getStringExtra ( "raw_json" );
ThreadMessageViewModel viewModel = new ViewModelProvider ( this ). get ( ThreadMessageViewModel . class );
if (rawMessage != null ) {
BaseMessage parentMessage = BaseMessage . processMessage ( new JSONObject (rawMessage));
viewModel . setParentMessage (parentMessage);
}
viewModel . getParentMessage (). observe ( this , msg -> {
header . setParentMessage (msg);
messageList . setParentMessage ( msg . getId ());
composer . setParentMessageId ( msg . getId ());
});
// Handle blocked user
if (isBlockedByMe) {
composer . setVisibility ( View . GONE );
unblock . setVisibility ( View . VISIBLE );
}
}
}
File reference:
ThreadMessageActivity.java
Step 3: Create ThreadMessageViewModel
Store parent message and expose LiveData:
class ThreadMessageViewModel : ViewModel () {
val parentMessage = MutableLiveData < BaseMessage >()
var id: Long = 0
private set
fun setParentMessage (message: BaseMessage ?) {
if (message != null ) {
id = message.id
parentMessage. value = message
}
}
}
public class ThreadMessageViewModel extends ViewModel {
private MutableLiveData < BaseMessage > parentMessage = new MutableLiveData <>();
private long id ;
public void setParentMessage ( BaseMessage message ) {
if (message != null ) {
this . id = message . getId ();
parentMessage . setValue (message);
}
}
public long getId () { return id; }
public LiveData < BaseMessage > getParentMessage () {
return parentMessage;
}
}
File reference:
ThreadMessageViewModel.java
Step 4: Hook Thread Entry from Message List
In your MessagesActivity, capture thread icon taps:
messageList. setOnThreadRepliesClick { context, baseMessage, template ->
val intent = Intent (context, ThreadMessageActivity:: class .java)
intent. putExtra ( "raw_json" , baseMessage.rawMessage. toString ())
intent. putExtra ( "reply_count" , baseMessage.replyCount)
context. startActivity (intent)
}
messageList . setOnThreadRepliesClick ((context, baseMessage, template) -> {
Intent intent = new Intent (context, ThreadMessageActivity . class );
intent . putExtra ( "raw_json" , baseMessage . getRawMessage (). toString ());
intent . putExtra ( "reply_count" , baseMessage . getReplyCount ());
context . startActivity (intent);
});
File reference:
MessagesActivity.java
Implementation Flow
User taps thread icon on a message.
Intent launches ThreadMessageActivity with raw message JSON.
ViewModel stores parent message and exposes via LiveData.
Header & MessageList render parent + replies.
Composer sends new replies under the parent message.
Live updates flow automatically via UI Kit.
Customization Options
Styling: Override theme attributes or call setter methods on views.
Header Height: threadHeader.setMaxHeight(...).
Hide Reactions: threadHeader.setReactionVisibility(View.GONE).
Filtering & Edge Cases
Group Membership: Verify membership before enabling composer.
Empty Thread: Show placeholder if no replies.
Blocked Users: Composer hidden; use unblock layout.
Blocked-User Handling
In UserDetailActivity, detect and toggle UI:
if (user.isBlockedByMe) {
composer.visibility = View.GONE
unblockLayout.visibility = View.VISIBLE
}
if ( user . isBlockedByMe ()) {
composer . setVisibility ( View . GONE );
unblockLayout . setVisibility ( View . VISIBLE );
}
File reference:
UserDetailActivity.java
Group vs. User-Level Differences
Scenario Behavior ReceiverType.USERDirect replies allowed if not blocked. ReceiverType.GROUPChecks membership before thread access. Blocked User Composer hidden; unblock layout shown. Not in Group Show option to join group first.
Summary / Feature Matrix
Feature Component / Method Show thread option setOnThreadRepliesClick()Display thread messages messageList.setParentMessage(parentMessage.getId())Show parent message header.setParentMessage(parentMessage)Compose reply composer.setParentMessageId(parentMessage.getId())Handle blocked users isBlockedByMe(), hide composer + show unblock UI
Next Steps & Further Reading
Android Sample App (Java) Explore this feature in the CometChat SampleApp:
GitHub → SampleApp Android Sample App (Kotlin) Explore this feature in the CometChat SampleApp:
GitHub → SampleApp