Build an Android chat app using Kotlin

No items found.
View GitHub Repo
July 19, 2019

When I last built a chat, it took me almost a week and still - there were finicky ongoing issues that required my attention! With CometChat, I managed to build a complete and reliable Android chat in under 3 hours, and now I'm here to teach you to do the same. CometChat has all the features you'd expect as well as has excellent documentation and tutorials (like this one) to help you with your implementation.

By the end of this tutorial, you should be able to implement a semi-complex Android group chat. We'll start by initializing the CometChat Android SDK, then move to logging the user in, fetching the list of groups, creating a new one, joining groups you weren't a part of and finally, the chat itself. CometChat is built for developers to make the task of implementing a chat much quicker, easier, and more reliable.

What we'll build

Here is a preview of what we'll build:

As you can see, the UI is pretty neat and clean resembling all the other chat apps you might have seen. Your messages appear on the right in blue, while others' messages are on the left in white.

I encourage you to follow along but you can also download the complete code on GitHub. I took care to write instructions in the README.

How to build an Android chat

The first thing we need to do is follow the docs to kick-start our chat app using CometChat. You can create a free CometChat account.

  1. Get your applications keys after signing up for CometChat. It is very easy to create a free account and get started. Signup for CometChat and then:
    a. Create a new app here

Hold your horses ‚ö†ÔłŹūüźī!
To follow this tutorial or run the example source code you'll need to create a V1 application.

v2 will be out of beta soon at which point we will update this tutorial.

b. Click "Explore" and then head over to the **API Keys** section and click on the **Create API Key** button  

c. Enter a name and select the scope as Auth Only

d. Now note the API Key and App ID

  1. Add the CometChat dependency in your Gradle files
    a. First, add the repository URL to the project level build.gradle file in the repositories block under the allprojects section:
  2. allprojects {
     repositories {
       maven {
         url "https://dl.bintray.com/cometchat/pro"
       maven {
         url "https://github.com/jitsi/jitsi-maven-repository/raw/master/releases"
  3. b. Then, add the CometChat SDK to the app level build.gradle file in the dependenciessection:
  4. dependencies {
     implementation 'com.cometchat:pro-android-chat-sdk:1.5.+'
  5. c. Then add the following lines to defaultConfig section of the app level gradle file:
  6. defaultConfig {
     ndk {
       abiFilters "armeabi-v7a", "x86"
  7. d. Finally, add the below lines android section of the app level gradle file:
  8. android {
      compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
  9. Next, initialize CometChat in the code in WelcomeActivity.kt:
  10. val appID:String="APP_ID"

    CometChat.init(this,appID, object : CometChat.CallbackListener<String>() {
     override fun onSuccess(p0: String?) {
        Log.d(TAG, "Initialization completed successfully")

      override fun onError(p0: CometChatException?) {
        Log.d(TAG, "Initialization failed with exception: " + p0?.message)

After you've successfully done that, let's jump straight into code and explain what we're going to be doing. We need to:

  • Log the user in
  • Get the group list
  • Join a group
  • Participate in the chat

On the Login screen, you need to provide the UID (User ID) to log in. There are five premade users which we can use for development. CometChat's predefined users have following IDs: SUPERHERO1, SUPERHERO2, SUPERHERO3, SUPERHERO4 and SUPERHERO5. We can use any of these UIDs to login.

The method that gets called is attemptLogin which looks like this:

private fun attemptLogin() {
   val UID = usernameEditText.text.toString()
   CometChat.login(UID, GeneralConstants.API_KEY, object : CometChat.CallbackListener<User>() {
       override fun onSuccess(user: User?) {

       override fun onError(p0: CometChatException?) {
           Toast.makeText(this@LoginActivity, p0?.message, Toast.LENGTH_SHORT).show()

After successfully logging the user in, you get the User object back. You don't have to save the logged in user manually, CometChat does it for you, and you can always access the user by using CometChat.getLoggedInUser() method. In onSuccess we simply redirectToMainScreen which does what it's name suggests.

Then the next thing to do is to fetch the list of groups. There's already a predefined group that all users belong to, called "Comic Heroes' Hangout". Again, with CometChat API, we get the groups like this:

private fun refreshGroupList() {
   // Get all the groups visible to this user
   // Since we're working with public groups only, all users should see all of them
   var groupRequest: GroupsRequest? = GroupsRequest.GroupsRequestBuilder().build()

   groupRequest?.fetchNext(object : CometChat.CallbackListener<List<Group>>() {
       override fun onSuccess(p0: List<Group>?) {

       override fun onError(p0: CometChatException?) {
           Toast.makeText(this@MainActivity, p0?.message, Toast.LENGTH_SHORT).show()

List of all groups

Upon getting the groups back, we can update the list of groups shown on the screen. The updateUI method is fairly simple - it just shows the newly fetched groups:

private fun updateUI(groups: List<Group>?) {
   val adapter = GroupsAdapter(groups, this)
   groupsRecyclerView.adapter = adapter

After that, you should be able to see at least that 1 group, and possibly more if you've created them.

The UI is pretty basic, but groups contain heaps more data to show if you needed.

In the list of groups, you can see that the ones you're a part of say JOINED and others do not. Since all the groups are public, everyone can join any group, no need for a password or any invitation or anything - just  tap on a group and you'll join it. Upon joining, you can participate in the chat. The logic for determining whether to open group chat or try to join a group is outlined in these few lines of GroupsAdapter.kt:

holder.container.setOnClickListener {
   if (group.isJoined) {
   } else {

This is how attemptJoinGroup looks, and in it's calling updateJoinedStatus to display the JOINED label in the list:

private fun attemptJoinGroup(group: Group) {
   // Try to join the group
   CometChat.joinGroup(group.guid, group.groupType, group.password, object : CometChat.CallbackListener<Group>() {
       override fun onSuccess(p0: Group?) {

       override fun onError(p0: CometChatException?) {
           Toast.makeText(context, p0?.message, Toast.LENGTH_SHORT).show()

private fun updateJoinedStatus(group: Group) {
   groups!!.forEach {
       // If successful, in order the show "JOINED" on that group, go through all of them, find the one we just joined,
       // And set Joined = true
       if (it.guid == group.guid) {

We finally come to the most crucial part - the actual chat screen. I've used a regular RecyclerView to display messages, and this portion of the docs to implement the actual messaging. With some easy callbacks, you can listen for incoming messages and display them as they come.

The code to send the message:

private fun attemptSendMessage() {
   // Attempts to send the message to the group by current user
   val text = messageEditText.text.toString()
   if (!TextUtils.isEmpty(text)) {
       val receiverID: String = group!!.guid
       val messageType: String = CometChatConstants.MESSAGE_TYPE_TEXT
       val receiverType: String = CometChatConstants.RECEIVER_TYPE_GROUP

       val textMessage = TextMessage(receiverID, text, messageType, receiverType)

       CometChat.sendMessage(textMessage, object : CometChat.CallbackListener<TextMessage>() {
           override fun onSuccess(p0: TextMessage?) {

           override fun onError(p0: CometChatException?) {


addMessage method merely adds a new message at the end and scrolls to it:

private fun addMessage(message: TextMessage?) {
   messagesRecyclerView.smoothScrollToPosition(messagesAdapter.itemCount - 1)

We also need to attach the listener responsible for getting incoming messages in onResume and remove it in onPause:

override fun onResume() {
   // Add the listener to listen for incoming messages in this screen
   CometChat.addMessageListener(listenerID,object :CometChat.MessageListener(){
       override fun onTextMessageReceived(message: TextMessage?) {
       override fun onMediaMessageReceived(message: MediaMessage?) {

override fun onPause() {

And finally, the class responsible for showing all the messages - the MessagesAdapter.kt. It is simply filling in some data from the TextMessage class, such as the sender's name and the actual content. It's also determining whether the message is from currentUser - that is, the user logged in on this device or not and changes the layout accordingly. That's done using two different ViewTypes in the RecyclerView like so:

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MessageViewHolder {
   if (viewType == GeneralConstants.MY_MESSAGE) {
       return MessageViewHolder(LayoutInflater.from(context).inflate(R.layout.my_message_layout, parent, false))
   return MessageViewHolder(LayoutInflater.from(context).inflate(R.layout.others_message_layout, parent, false))

override fun getItemViewType(position: Int): Int {
   if (isCurrentUserMessage(messages[position])) {
       return GeneralConstants.MY_MESSAGE
   return GeneralConstants.OTHERS_MESSAGE

private fun isCurrentUserMessage(message: TextMessage?): Boolean {
   val currentUserId = CometChat.getLoggedInUser()?.uid
   return currentUserId!! == message?.sender?.uid

We are inflating a different layout depending on whether the message came from us or someone else. The layouts are my_message_layout.xml and others_message_layout.xml  respectively. Also, the onBindiewHolder method is pretty simple, it just fills out the content and uses UI Avatars to load the images into circular ImageViews with Glide:

override fun onBindViewHolder(holder: MessageViewHolder, position: Int) {
   holder.messageTextView.text = messages[position]?.text
   // Check if the sender is the current user
   Glide.with(context).load(GeneralConstants.AVATARS_URL + messages[position]?.sender?.name).into(holder.avatarImageView)

That's it, and now we're down to testing. To test the app properly, you should run it and log in as one of the test users. You can also launch two emulators side by side and login with two different users and play around with the chat. It should look something like this:

CometChat group chat in action


CometChat is both simple and powerful. With intuitive API and great docs, you can quickly master this library and make some astonishing chat applications. The options are truly abundant, and I feel like I've only scratched the surface with this demo. There's a lot I didn't cover:

  • private/password protected groups
  • proper sign up/log in
  • list of participants in the group and actions on them (kick/ban/unban/change user's scope)
  • other types of messages, not just text

What we did learn is how easy it can be to implement the chat in your application. Hopefully, some of these very interesting topics will be covered in some next tutorial, where we can dive a bit deeper into the power of CometChat.

Related Posts

No items found.
No items found.
No items found.

Try Us for Free 

For as Long as You Like!