Add Livestream Chat to your Android App

5 min read
JC M.
JC M.
Published May 13, 2020 Updated December 23, 2021

Live streaming apps have become the most popular type of application in the App Stores. Big companies, like Google, Amazon, Facebook, and Twitter, have, at least, one app offering this kind of service. For example: YouTube, Twitch, Instagram, and Periscope. All of those have a common companion feature: Livestream Chat.

Livestream Chat is a crucial feature to improve the user's engagement on your app. It allows your users to interact with others in real-time. In this article, I am going to show you how easy it could be to have Livestream Chat in your Android app in less than 20 minutes.

The result will look similar to this:
Animation shows a chat room with a video on top

Sample Overview

The sample project will consist of two screens. The first of them shows a list of items. Each one represents a video. When the user clicks on one of them, they will navigate to another screen where the video starts to play. Below the video, there is a chat where all messages are, and there is a textbox that allows you to write a new one and send it. The app can be opened in multiple devices at the same time, and messages are sent/received in real-time in all devices

Because this is a sample project, you will find some datastores on the Models file. There is a list of videos that simulates the result of an API call. To also simplify the sample, the user on the app is selected randomly. In a real app, there will be a login process, receiving a proper JWT token to use with the Stream Services.

To keep the sample as simple as possible, we have not added any extra layer to the project nor created any complex architecture. Still, you can (and should) use the architecture you are most familiar with.

You can find the complete code sample can in the following GitHub repository:
https://github.com/GetStream/livestream-chat-android-example

Initialize the Stream SDK

Stream provides three complementary SDKs that you can use on your app:

In this example, we are going to use the low-level client.
The first step we need to take is to initialize the chat SDK with the API Key. To do that, we will use the ChatClient.Builder class, and we are going to enable logs on it to be able to see what is happening during the debugging process.

val apikey: String = "api_key"
val client: ChatClient = ChatClient.Builder(apikey, this.applicationContext)
   .logLevel(ChatLogLevel.ALL)
   .build()

Once we have started the ChatClient, we need to specify which user will use it. To set the current user, the ChatClient has a method setUser() that can we can configure with different attributes. It will need a User object that represents the user that will be chatting and store some information such as id, name, profile picture, and the token that identifies this user. If the JWT token used by our server has an expiration time, we can configure it with a function that will refresh the token every time it expires. The last attribute we will need to pass to this method is a callback that will be called when the process finishes with a success or failure message.

val token: String = "user jwt token"
val user = User("user_id").apply {
   extraData["name"] = "John"
   extraData["image"] = "https://server.com/profile/picture.jpg"
}

client.setUser(user, token, object : InitConnectionListener() {
   override fun onSuccess(data: ConnectionData) {
       // user has been connected successful
   }

   override fun onError(error: ChatError) {
       // An error has succeeded 
   }
})

That's it! We have our chat client configured and ready to start using it.

Building your own app? Get early access to our Livestream or Video Calling API and launch in days!

Create a New Channel

Once we have the ChatClient initialized, we need to obtain the channel where messages are sent. Stream provides some pre-configured types of channels with custom rules and allows you to create your own types. The most common types needed are already configured, and you can check them here. In our example we are going to use the Channel Type "Livestream". To interact with a channel, we will need to create a ChannelController that will help us query the Stream Services.
To create the ChannelController we need to indicate the ChannelType and the id that will identify it.

val channelType = "livestream"
val channelId = "channel_id"
val channelController: ChannelController = chatClient.channel(channelType, channelId)

Now that we have our ChannelController ready, we can use it to obtain the message history. To do it we use the method query() with a QueryChannelRequest. We can configure QueryChannelRequest to request different information to the Stream server. In the following example, we are giving a name to the channel and asking for the last 100 messages sent.

val data: Map<String, Any> = mapOf("name" to "The name of the channel")
channelController.query(
   QueryChannelRequest()
       .withData(data)
       .withMessages(100)
       .withWatch()
).enqueue {
   when (it.isSuccess) {
       true -> {
           // Channel has been created and we can get it calling to the data() method
          val channel: Channel = it.data()
          // Inside of the channel, we can find received messages
          showMessages(it.data().messages)
       }
       false -> {
           // Something went wrong, we have the error on the error() method
           handleError(it.error())
       }
   }
}

Subscribe to New Messages

We have the channel and the last 100 messages sent to it. Now we want to receive any new messages. To do that, we can subscribe to new events happening on the channel. The different types of events that can occur on a channel are detailed here, but we only need to get the ones that represent a new message. To do that, we need to add a filter to our subscription. The following code shows you how to do it:

val eventType: String = "message.new"
val subscription = channelController
   .events()
   .filter(eventType)
   .subscribe { chatEvent -> renderMessage(chatEvent.message) }

Now, every new message sent to the channel will be received on the lambda we pass to the subscribe() method, and we are ready to render the new message.
When the user goes out of the stream, we don’t want to receive messages anymore, so we will need to unsubscribe and stop watching the channel.

channelController.stopWatching()
subscription.unsubscribe()

Send a New Message

For the last step, we are going to cover sending messages to the channel. To post a new one, we need to use the previous ChannelController we have created and call the method sendMessage() that receives the message as a parameter.

val newMessage = Message().apply { text = "It's the message we will send" }
channelController.sendMessage(newMessage).enqueue {
   when (it.isSuccess) {
       true -> {
           // The message was sent, and we have all extra data on the message that return data() method
           val sentMessage = it.data()
       }
       false -> {
           // There was an error sending the message, you can check it on the error() method
           it.error()
       }
   }
}

Final Thoughts

And that is all the logic you need to implement a Livestream chat. In the repository example, you can see how I designed the views for it, they are remarkably simple, and you can customize them to fit your app. (Also, check out our UX best practices for livestream chat.)

I hope you now understand how easy it is to integrate Stream in your app to build a simple live streaming chat. In the sample, we only cover basic integration. Still, Stream provides you a lot of features like: Roles, delete/update messages, reactions, push notifications, and all of them are available in multiple platforms: Android, iOS, React, and Flutter.
You can check the documentation and there are additional messaging tutorials on our blog that you might find helpful.

decorative lines
Integrating Video With Your App?
We've built an audio and video solution just for you. Launch in days with our new APIs & SDKs!
Check out the BETA!