A couple of weeks ago, my boss tasked me with adding the group chat functionality to our existing Android app, but time was of the essence (I think it was Wednesday, and he said it would be great if we could have it by weekend, it just needed to work).

Given a nifty bonus we were promised if we can deliver in such a record time, we decided to give it a go. In spite of this huge constraint, I had to figure out a way to reliably implement a group chat. This is why I decided it’s best to resort to 3rd party libraries, which tend to be a real time-saver and are usually much more reliable than what I could have coded in a few days. I chose CometChat for the back-end logic, and ChatKit for the UI. These two libraries are both very powerful and offer a wide variety of functionalities, and are yet so simple to integrate and use. It took me slightly less than an hour to have a fully functional version of a chat app. Had I not had to integrate the chat into an already existing code, it would have been more like 30 minutes. I know this for sure, because prior to writing this tutorial, I actually wrote a demo app which took that much. I didn’t spend too much time customizing anything, but it is still quite appealing to the eye and works like a charm.

We’re going to cover every step of the process, from creating an empty new Android project, to having a fully functional nice looking chat app. We’ll start by including both the libraries we’ll be using, move on to logging in with CometChat and displaying a list of group chats, to implementing the sending and receiving of message and displaying them with the help of ChatKit. Finally, we’ll fetch previous messages and display those too.

Here’s how it looks:
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 grey.

Link to the code on GitHub: https://github.com/cometchat-pro-tutorials/quick-group-chat-java

In order to get the best out of this tutorial, either download the code from GitHub, follow along and examine it, or try writing the whole thing for yourself using steps below and the documentation.

The implementation

Without further ado, let’s jump straight into it. There’s a couple of things we need to do:

  • Sign up for CometChat
  • Include the libraries
  • Initialize and Log in with CometChat
  • Fetch and display the list of groups
  • Use CometChat to send and receive messages
  • Utilize ChatKit to display the messages
  • Fetch previous messages and display them

Sign up for CometChat

Follow this link and create an account (here is a link to the docs also), then create a new app and get the API keys we’ll need later to initialize it.

Include the libraries

For including CometChat, add this to your project level build.gradle:

allprojects {
  repositories {
    maven {
      url "https://dl.bintray.com/cometchat/pro"
    }
  }
}

Add these few lines in your app level build.gradle:

dependencies {
  implementation 'com.cometchat:pro-android-chat-sdk:1.8.8'
}


defaultConfig {
  ndk {
    abiFilters "armeabi-v7a", "x86"
  }
}


android {
  compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}

For including ChatKit, add this line to your dependencies:

implementation 'com.github.stfalcon:chatkit:0.3.3'

Initialize and Log in with CometChat

This process is fairly simple, just call this method in onCreate in order to initialize CometChat:

private void initCometChat(){
    CometChat.init(this, Constants.COMET_CHAT_APP_ID, new CometChat.CallbackListener<String>() {
        @Override
        public void onSuccess(String successMessage) {
            Log.d(TAG, "Initialization completed successfully");
        }
        @Override
        public void onError(CometChatException e) {
            Log.d(TAG, "Initialization failed with exception: " + e.getMessage());
        }
    });
}

Note that you need to provide AppId we mentioned earlier, that you got from the CometChat dashboard when you created a new app.

Now just log the user in on the tap of a button. You can create your own users in CometChat, but you can also use the already predefined users to log in. There’s 5 of them and they have the user IDs: superhero1, superhero2, superhero3, superhero4 and superhero5. You can use those for testing the chat, and later add sign up. This is how we log the user in:

private void loginWithCometChat(String username) {
    CometChat.login(username, Constants.COMET_CHAT_API_KEY, new CometChat.CallbackListener<User>() {
        @Override
        public void onSuccess(User user) {
            redirectToNextScreen();
        }
        @Override
        public void onError(CometChatException e) {
            Log.d(TAG, "Login failed with exception: " + e.getMessage());
        }
    });
}

Note that here we’ll be using the ApiKey that we also got from the CometChat dashboard. I extracted those two values into a Constants class just to keep the code tidier. redirectToNextScreen just starts a new activity, where we’ll have a list of groups:

private void redirectToNextScreen() {
    GroupListActivity.start(this);
}

Fetch and display the list of groups

We’re using a RecyclerView to display a list of groups this user is a part of. First, we’ll fetch the groups from CometChat like this:

private void getGroups() {
    GroupsRequest groupsRequest = new GroupsRequest.GroupsRequestBuilder().build();
    groupsRequest.fetchNext(new CometChat.CallbackListener<List<Group>>() {
        @Override
        public void onSuccess(List<Group> groups) {
            updateList(groups);
        }

        @Override
        public void onError(CometChatException e) {

        }
    });
}

Upon success, we’ll just create and set the adapter for our RecyclerView:

private void updateList(List<Group> groups) {
    GroupsAdapter groupsAdapter = new GroupsAdapter(groups, this);
    groupsRecyclerView.setAdapter(groupsAdapter);
}

GroupsAdapter will display only the name of the group, omitting other pieces of information. There’s already a predefined group called “Comic Hero’s hangout” which you should be able to see. I’ve kept the layout simple in the demo app. We’ve also set the listener on each Group that opens up the chat screen, making our bind method look like this:

public void bind(Group group) {
    groupNameTextView.setText(group.getName());
    containerLayout.setOnClickListener(v -> {
        GroupChatActivity.start(context, group.getGuid());
    });
}

We’re ready to start implementing the actual chat part of the app.

Use CometChat to send and receive messages

In order to send a message, we need to have the id of the group we’re sending to. So we’re passing the groupId through the intent when starting this activity:

public static void start(Context context, String groupId) {
    Intent starter = new Intent(context, GroupChatActivity.class);
    starter.putExtra(Constants.GROUP_ID, groupId);
    context.startActivity(starter);
}

And we’re getting it in onCreate:

groupId = getIntent().getStringExtra(Constants.GROUP_ID);

After that, we can just call this method to send a message:

private void sendMessage(String message) {
    TextMessage textMessage = new TextMessage(groupId, message, CometChatConstants.MESSAGE_TYPE_TEXT, CometChatConstants.RECEIVER_TYPE_GROUP);

    CometChat.sendMessage(textMessage, new CometChat.CallbackListener<TextMessage>() {
        @Override
        public void onSuccess(TextMessage textMessage) {
            addMessage(textMessage);
        }

        @Override
        public void onError(CometChatException e) {

        }
    });
}

addMessage will just append the message to the end of our list, we’ll talk about that in just a moment, because we’ll be using ChatKit adapter for this.
For receiving the incoming messages, we need to add a listener in onCreate :

private void addIncomingMessageListener() {
    CometChat.addMessageListener(listenerID, new CometChat.MessageListener() {
        @Override
        public void onTextMessageReceived(TextMessage textMessage) {
            addMessage(textMessage);
        }

        @Override
        public void onMediaMessageReceived(MediaMessage mediaMessage) {

        }

        @Override
        public void onCustomMessageReceived(CustomMessage customMessage) {

        }
    });
}

Since we’re only concerned about TextMessages for now, we’ll just leave the other 2 methods empty. When we receive a message, we again call addMessage so that it’s shown at the end of the list. That’s it, with these 2 methods, the chat should work. Now we just need to display it.

Utilize ChatKit to display the messages

We’ll use ChatKit to display both the messages and the input field for sending a message. This is how our layout for the activity will look like:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".GroupChatActivity">
    <com.stfalcon.chatkit.messages.MessagesList
        android:id="@+id/messagesList"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@id/input"
        app:layout_constraintTop_toTopOf="parent"/>
    <com.stfalcon.chatkit.messages.MessageInput
        android:id="@+id/input"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:inputHint="@string/enter_a_message"/>
</androidx.constraintlayout.widget.ConstraintLayout>

Input is on the bottom, while MessageList, a widget that’ll display every message, takes up the rest of the space. Now we need to connect the MessageInput with our sendMessage method:

messageInput.setInputListener(input -> {
    sendMessage(input.toString());
    return true;
});

That was quite simple. The only thing that remains is displaying the message list. For this, we’ll be using a MessagesListAdapter provided by ChatKit:

ImageLoader imageLoader = (imageView, url, payload) -> Picasso.get().load(url).into(imageView);
MessagesListAdapter<MessageWrapper> adapter = new MessagesListAdapter<>(CometChat.getLoggedInUser().getUid(), imageLoader);

We’re providing the ImageLoader in order to load the user’s avatars. If you don’t wish to show those, just pass null as the second parameter. One more thing we need to discuss is MessageWrapper class. This is the bridge between CometChat’s Message and ChatKit’s Message classes. Let’s take a look at it:

public class MessageWrapper implements IMessage {
    private TextMessage message;
    public MessageWrapper(TextMessage message) {
        this.message = message;
    }
    @Override
    public String getId() {
        return message.getMuid();
    }
    @Override
    public String getText() {
        return message.getText();
    }
    @Override
    public IUser getUser() {
        return new UserWrapper(message.getSender());
    }
    @Override
    public Date getCreatedAt() {
        // * 1000 to get milliseconds
        return new Date(message.getSentAt() * 1000);
    }
}

IMessage is the interface that we need to implement in order to use ChatKit’s MessagesListAdapter , while TextMessage is a CometChat class that contains all the info about our messages. So when CometChat gives us a TextMessage in one of it’s callbacks, we merely create a new MessageWrapper(textMessage), and pass that to ChatKit to display.

Finally, let’s examine the addMessage method:

private void addMessage(TextMessage textMessage) {
    adapter.addToStart(new MessageWrapper(textMessage), true);
}

Chat app in action, sending and receiving messages from multiple people

It wraps the CometChat message in our MessageWrapper so ChatKit would know how to display it via the IMessage interface. And we should be able to see our messages sent and received at this point. This is how it should look:

There’s only 1 more thing left to do.

Fetch previous messages and display them too

We need to get the message history in order to make this a fully functional chat app. We do this by calling fetchPrevious on a MessageRequest:

private void getPreviousMessages() {
    MessagesRequest messagesRequest = new MessagesRequest.MessagesRequestBuilder().setGUID(groupId).build();
    messagesRequest.fetchPrevious(new CometChat.CallbackListener<List<BaseMessage>>() {
        @Override
        public void onSuccess(List<BaseMessage> baseMessages) {
            addMessages(baseMessages);
        }

        @Override
        public void onError(CometChatException e) {

        }
    });
}

And addMessages just wraps each message and adds them to the adapter:

private void addMessages(List<BaseMessage> baseMessages) {
    List<MessageWrapper> messageWrappers = new ArrayList<>();
    for (BaseMessage message : baseMessages) {
        messageWrappers.add(new MessageWrapper((TextMessage) message));
    }
    adapter.addToEnd(messageWrappers, true);
}

Conclusion

When time is running low, 3rd party libraries can work wonders. This tutorial should be a stepping stone in your introduction to CometChat and ChatKit. They both offer much more than what was covered here. CometChat pretty much covered everything related to back-end for us, while ChatKit saved us some hassle dealing with the UI. Using CometChat also meant we didn’t need our own server, developing it, deploying, debugging, and ultimately wasting a ton of time on something we got out-of-the-box here. For an individual developer and a company alike, if you’re looking to jump start your app, this is the way to do it. Ultimately, it’s up to you whether you want to build everything from scratch, or use an already tested and proven product, which took months, if not years to build.