Engineering

Build in-app chat using Kotlin: part 2

Alex Preston
Alex Preston Solutions Engineer
Share

Get Started!

Sign up for a full-featured 30 day free trial. No credit card required.

Free Trial

Introduction

In the first part of this guide, ‘Build in app chat using Kotlin: part 1’, we built out the login, and the ability to create and list channels. In this follow-up blog post, we will create the UI for the ChatActivity, build the MessageAdapter which handles setting the UI components, and implement the ChannelActivity class. This guide only covers sending/receiving User Messages. To see how to send File Messages, please visit Sendbird Documentation.

In-app chat using Kotlin - diagram

Assumptions

This tutorial assumes prior knowledge of Android and Android concepts, and was built using Android Studio: 4.0.2, Android Version: 10 API 29, Kotlin: 1.3.72, and Sendbird Core SDK: 3.0.148. Here is the completed source code for both part 1 and 2 of this guide.

UI for Channel Activity

Sendbird UI for channel activity

The first step is to create a UI for how the chat will look. We will add an AppBarLayout with a “Back” button on the top to return to the ChannelListActivity. Below that we’ll add a RecyclerView to show the actual messages, and finally on the bottom, we’ll add a simple layout to handle entering and sending messages. 

Activity_chat.xml

Now that the UI skeleton is done, we need to create two different item views for the messages themselves because we will have a different UI for messages that are sent by the current user, and another UI for messages that are sent by others in the chat. (Note: As you implement more types of messages, you’ll have more of these .xmls.)The first .xml is for messages that are from the “Me” perspective, or messages sent by the current user. For this we have opted to have a TextView for the actual message, this is wrapped in a Cardview. Surrounding this TextView are other TextViews for items such as the date. 

Item_chat_me.xml

Now that theUI is complete, we are going to implement the MessageAdapter.kt class. This class  handles attaching the data that is passed to it, to a particular view in the RecyclerView. 

At this point, you will create a class called MessageAdapter.kt. This class extends the RecyclerView.Adapter<RecyclerView.ViewHolder>(), so you need to make sure to implement the following methods:

  • onCreateViewHolder: This function  returns the customViewHolder that corresponds to the type of message that is there. 
  • getItemViewType: This figures out what kind of message it is. Currently, we have only implemented UserMessage. In this function we will determine whether it is a “Me” message or an “Other” Message, and return accordingly. 
  • onBindViewHolder: This function binds the messages to the views. 
  • getItemCount: This function returns the current position. 

There are two additional functions that need to be added:

      • loadMessages: This function loads the initial past messages that are received in the ChannelActivity. 
      • addFirst: This function adds recently sent or received messages to the adapter. Obviously, both of these messages need to call notifyDataSetChanged() to handle updating the RecyclerView. 

MessageAdapter.kt


After handling the essential functions for a RecyclerView adapter, we need to implement our own customViewHolders. There are two inner classes denoted by:

    • MyUserHolder:This class simply binds the respective message sent by “Me” to the item, which we created the view for earlier.

MyUserHolder.kt

    • OtherUserHolder: This class simply binds the respective message sent by “Other” to the item, which we created the view for earlier.

OtherUserHolder.kt

For the sake of a cleaner look, we also added an object that has two functions to help with date formatting: 

DateUtil.kt

This completes the code for the MessageAdapter class. Here's completed class for MessageAdapter.kt.

ChannelActivity.kt

Now that we have implemented the UI, and taken care of the adapter to connect the UI to the passed data, we will now implement the ChannelActivity.kt. The following class handles a few things: It sets up the RecyclerView and adapter, handles getting and entering the channel passed by either the CreateChannelActivity or the ChannelListActivity, and handles sending and receiving messages. 

First, you need to create a ChannelActivity.kt class. In the onCreate function, set the contentView and call two functions to handle the setup.

onCreate

The first function sets up the RecyclerView and the MessageAdapter we just created. This code follows a pretty basic implementation for instantiating a RecyclerView. Be sure to pass the context of the activity for the MessageAdapter because you will need that when setting the image, as we did above.

setUpRecyclerView.kt

The second function handles setting the two buttons on the activity: Back and Send. The Back button is relatively explanatory, so let's focus on the Send button.

setButtonListeners

For the Send button we use a method called sendMessage. This function takes the text from the editText, and sets it on the param of UserMessageParams(). There is a lot more you can do with UserMessageParams(), but for the sake of simplicity we will just add the message. We’ll then take the groupChannel instance and .sendMessage(). Upon the return that it was successfully sent, we will add it to the adapter, and then clear the editText.

sendMessage

Now that we have completed the onCreate call, let’s get to the onResume call. This call is where we will handle getting the passed channel, and where we will register the channel handler so we can get various events, in this case the onMessageReceived event. 
First, we want to get the channelURL from the intent, and for the sake of visibility we will move this to a separate method.

getChannelUrl


After we have the channelURL, we need to make a call GroupChannel.getChannel(). This call takes the channelURL and retrieves the channel object so we can do various things like send messages and get relevant channel information. Once it returns successfully with the channel, we need to set the channel, and be sure to call getMessages(). 

This function is pretty straightforward. It creates a previousMessageListQuery , loads the messages, and then calls loadMessages on the adapter. This gets all the previous messages in the conversation. This function supports pagination so you can get the entire conversation history.

getMessages()

The final step in the onResume call is to set a channel handler. The channel handler is how you can get various events such as typing indicators, message read, and message delivered events, as well as onMessageReceived events. The only method we implemented was onMessageReceived. This event fires every time a message comes in from another user. Once we get the event we simply add it to the adapter, as shown in the following code:

onResume()

That completes the code for the ChannelActivity class. See the following completed class for ChannelActivity.kt

Conclusion

This blog post demonstrated how to create a chat UI, and hook up that chat UI to be able to send/receive and display messages. This guide serves as a stepping stone to the many things you can do with the Sendbird SDK. From what we have just implemented, you can easily start to incorporate more types of messages, add a more complete view into the message life cycle, add push notifications, typing indicators, translations, and so much more. 

Categories: Engineering