Subscribe to Email updates

Please use a valid email address.

Privacy Policy.
Android Chat Tutorial: Building a Messaging UI

Android Chat Tutorial: Building a Messaging UI

May 09, 2017

Despite their growing prevalence, chat and messaging apps continue to be tedious to implement. Official documentation is non-existent, while unofficial tutorials are scarce and generally outdated.

Google Allo's Android chat UI

Colorful chat bubbles filled with text, images, even playable media--how do they do it? The answer is surprisingly simple: RecyclerViews, coupled with the ViewHolder pattern.

This tutorial walks you through the steps required to build a quality messaging UI.

Setting up the Activity

In this tutorial, we'll create a dedicated activity to host our messages. Let's call it MessageListActivity. The primary component in this activity is a RecyclerView that fills most of the screen. To keep ahead of the curve, a ConstraintLayout will be used as the root ViewGroup.

In addition to displaying message history, chat UIs typically allow the user to send messages through a chatbox. We'll position this chatbox at the bottom of the screen using constraints. This will anchor it to the soft input keyboard that pops up when the user types.


...waiting for Gist...

This creates two elements:

  1.  A flexible chatbox that expands according to the length of the message being typed
  2.  A RecyclerView that designates the remaining space to past messages

It will look like the following image:

layout 1

Creating a list item for each message

Use a separate XML file to define the layout of each item (i.e. message) for ListViews and RecyclerViews. It is common practice for each message to contain the sender’s name, their profile image, and a timestamp.

Screen Shot 2017-04-04 at 5.09.24 PM

Since the chat bubble's alignment typically indicates the message's owner, it could be redundant to display the sender's profile image and name for every message. In the above image, for example, the right-aligned chat bubble indicates that it belongs to the sender, so we need not include the image or name. Most chat clients choose to discard these components altogether. We will do the same by creating two different ViewHolder's:

  1. SentMessageHolder for messages that “I” have sent
  2. ReceivedMessageHolder for messages sent by others

To create the above image, we must first create a chat bubble in an XML file. Once again, this is surprisingly simple:

  1. Set a rounded rectangle as the background for TextView
  2. Adjust the paddings
  3. Align the text


...waiting for Gist...

Voila! We now have a handsome chat bubble housing the message.

Screen Shot 2017-04-04 at 5.19.36 PM

You can appropriately position the other TextViews using constraints. Be sure to create two more constraints before moving on:

  1. Be sure to set your root layout’s height to wrap_content, so it can accommodate messages containing a single line and messages containing more than a single line
  2. Set the message body’s max_width to an appropriate threshold. Without this constraint, the chat bubble will fill the entire screen's width, and will look clumsy.

Now let's apply this model to both the received and sent messages.

Received Messages


...waiting for Gist...

This produces the following image for received messages.

Screen Shot 2017-04-04 at 5.25.31 PM

Sent Messages

For sent messages, align the chat bubble to the right, and remove the sender's name and profile image.


...waiting for Gist...

Creating an Adapter for the RecyclerView

Populate the RecyclerView with the above XML items by creating an adapter that extends RecyclerView.Adapter. This adapter will accomplish three things:

  1. Store a list of messages
  2. Determine whether a message is sent or received
  3. Inflate the appropriate layout within RecyclerView.

But before venturing any further, we need a list of messages!

Engineering a backend for real-time messaging is, however, beyond the scope of this tutorial. We'll therefore proceed with the models in SendBird’s chat SDK. It roughly assumes the following structure:

Generic Message and User models

class Message {
    String message;
    User sender;
    long createdAt;

class User {
    String nickname;
    String profileUrl;

Since it is common to design messaging implementations in this manner, you will hopefully be able to follow this tutorial with minimal changes to your code.

Now, let's create an adapter and name it MessageListAdapter. It will hold a List of Messages that will be displayed within a RecyclerView.

...waiting for Gist...

By default, an adapter requires at least one RecyclerView.ViewHolder. It is a layout that can be inflated and bound by the objects it holds. In our case, two ViewHolders are needed:

  1. SentMessageHolder to hold messages that "I" sent
  2. ReceivedMessageHolder to hold messages that “I” have received from others

We'll write these to be private inner classes of MessageListAdapter.

Each ViewHolder holds member views that can be bound to particular information contained in a message. For example, TextView messageText binds to a message’s content, while nameText binds to the name of a message’s sender.

Antonio Leiva suggests that we implement a bind(object) method within the ViewHolder class. This gives view binding to the ViewHolder class rather than to onBindViewHolder. It therefore produces cleaner code amidst multiple ViewHolders and ViewTypes. It also allows us to add easily OnClickListeners, if necessary.

...waiting for Gist...

SentMessageHolder will be identical except that it will not have nameText and profileImage.

Once you complete ViewHolder, turn back to the adapter and override the necessary methods to

  1. Obtain a message from MessageList
  2. Determine whether it is a sent message or a received message
  3. Inflate the appropriate layout for the ViewHolder
  4. Pass the message to the ViewHolder for binding

Implementing this process is standard for most types of adapters, and pretty self-explanatory; therefore, we'll show the code for the full adapter without further explanation.

...waiting for Gist...

We've just completed the adapter. We can now display a list of messages, both sent and received, in the chat bubbles that we defined earlier.

Putting it all together

We've created all the components, and now we need to initialize them inside our Activity. Instantiate a RecyclerView and a MessageListAdapter with a list of messages, and voila! You've just created your own messaging UI.

...waiting for Gist...

You can build more advanced features like "image preview," animated GIFs within chat bubbles, and others. See examples of advanced chat UI at SendBird’s open source sample UI app! They build upon the use of RecyclerViews and adapters that we covered in this tutorial, and will help you create a production-level chat app with diverse features.

We're Hiring!
Help SendBird build the world's no. 1 messaging platform
We're Hiring!
Help SendBird build the world's no. 1 messaging platform
Related articles
Migrating chat made easy with Sync Server
Introduction Part of the challenge of migrating from one chat provider to another is not having a live migration solution ready. Building a live migration solution can be cost
Solutions Engineer
Don't try this at home: Why software engineers shouldn't build chat in-house
Before I helped co-found SendBird as the Chief Technology Officer, I built chat as a feature for two products. Both were consumer apps for families that required a real-time s
Chief Technology Officer
Extreme Optimization of AsyncStorage in React Native
 AsyncStorage is a unique built-in feature for storing data in React Native and a good way to store simple key-value data. To make the SendBird SDK less dependent on other pac
Software Engineer - Applications
© SendBird 2019. All rights reserved.
Follow us