/ SDKs / Android
SDKs
Chat SDKs Android v4
Chat SDKs Android
Chat SDKs
Android
Version 4

Message collection

Copy link

A MessageCollection instance allows you to swiftly create a chat view that includes all data. This page explains how to make a view using the collection.


Create a collection

Copy link

First, create a MessageCollection instance through the createMessageCollection() method. Here, you need to set a MessageListParams instance to determine the message order and the starting point of the message list in the chat view.

fun createMessageCollection() {
    // Create a MessageListParams to be used in the MessageCollection.
    val params = MessageListParams().apply {
        reverse = false
    }
    // You can add other query setters.
    val collection = SendbirdChat.createMessageCollection(
        MessageCollectionCreateParams(groupChannel, params).apply { 
            startingPoint = STARTING_POINT
        }
    )
}

Starting point

Copy link

The reference point for message retrieval in a chat view is startingPoint. This should be specified as a timestamp.

If you set the value of startingPoint to Long.MAX_VALUE, messages in the view are retrieved in reverse chronological order, showing messages from the most to least recent.

If you set the value of startingPoint to the message last read by the current user, messages in the view are fetched in chronological order, starting from the last message seen by the user to the latest.


Initialization

Copy link

After creating a MessageCollection instance, initialize the instance through the initialize() method. Here, you need to set MessageCollectionInitPolicy.

Policy

Copy link

The MessageCollectionInitPolicy property determines how initialization deals with the message data retrieved from the local cache and API calls. Because we only support MessageCollectionInitPolicy.CACHE_AND_REPLACE_BY_API at this time, messages in the local cache must be cleared prior to adding the messages from the Sendbird server.

PolicyDescription

CACHE_AND_REPLACE_BY_API

Retrieves cached messages from the local cache and then replaces them with the messages pulled from the Sendbird server through API calls.

KotlinKTX
// Initialize messages from the startingPoint.
fun initialize() {
    collection.initialize(
        MessageCollectionInitPolicy.CACHE_AND_REPLACE_BY_API,
        object : MessageCollectionInitHandler {
            override fun onCacheResult(cachedList: List<BaseMessage>?, e: SendbirdException?) {
                // Messages are retrieved from the local cache.
                // They can be outdated or far from the startingPoint.
            }

            override fun onApiResult(apiResultList: List<BaseMessage>?, e: SendbirdException?) {
                // Messages are retrieved through API calls from the Sendbird server.
                // According to MessageCollectionInitPolicy.CACHE_AND_REPLACE_BY_API,
                // the existing data source needs to be cleared
                // before adding retrieved messages to the local cache.
            }
        }
    )
}

Pagination

Copy link

Use the loadPrevious() and loadNext() methods to retrieve messages from the previous page and the next page.

When the loadPrevious() method is called, the Chat SDK first checks whether there're more messages to load from the previous page through hasPrevious. The same goes for hasNext and loadNext().

These methods have to be called during initialization as well.

Load previous messagesLoad previous messagesLoad next messagesLoad next messages
// Load the previous messages when the scroll reaches the first message in the chat view.
if (collection.hasPrevious) {
    collection.loadPrevious { messages, e ->
        if (e != null) {
            // Handle error.
            return@loadPrevious
        }
    }
}

Message events

Copy link

Use messageCollectionHandler to determine how the client app reacts to message-related events.

The following table shows possible cases where each event handler can be called.

HandlerCalled when

onMessagesAdded()

- A new message is created as a real-time event.
- New messages are fetched during changelog sync.

onMessagesDeleted()

- A message is deleted as a real-time event.
- Message deletion is detected during changelog sync.
- The value of the MessageListParams setter such as custom_type changes.

onMessagesUpdated()

- A message is updated as a real-time event.
- Message update is detected during changelog sync.
- The send status of a pending message changes.

onChannelUpdated()

- The channel information that is included in the user's current chat view is updated as a real-time event.
- Channel info update is detected during changelog sync.

onChannelDeleted()

- The current channel is deleted as a real-time event.
- Channel deletion is detected during changelog sync.
* In both cases, the entire view should be disposed of.

onHugeGapDetected()

- A huge gap is detected through background sync. In this case, you need to dispose of the view and create a new MessageCollection instance.

val collection = SendbirdChat.createMessageCollection(
    MessageCollectionCreateParams(groupChannel, messageListParams).apply {
        messageCollectionHandler = object : MessageCollectionHandler {
            override fun onMessagesAdded(context: MessageContext, channel: GroupChannel, messages: List<BaseMessage>) {
                when (context.messagesSendingStatus) {
                    SendingStatus.SUCCEEDED -> {
                        // Add messages to your data source.
                    }
                    SendingStatus.PENDING -> {
                        // Add pending messages to your data source.
                    }
                }
            }

            override fun onMessagesUpdated(context: MessageContext, channel: GroupChannel, messages: List<BaseMessage>) {
                when (context.messagesSendingStatus) {
                    SendingStatus.SUCCEEDED -> {
                        // Update the message status of sent messages.
                    }
                    SendingStatus.PENDING -> { // failed -> pending
                        // Update the message status from failed to pending in your data source.
                        // Remove the failed message from the data source.
                    }
                    SendingStatus.FAILED -> { // pending -> failed
                        // Update the message status from pending to failed in your data source.
                        // Remove the pending message from the data source.
                    }
                    SendingStatus.CANCELED -> { // pending -> canceled
                        // Remove the pending message from the data source.
                        // Implement code to process canceled messages on your end. The Chat SDK doesn't store canceled messages.
                    }
                }
            }

            override fun onMessagesDeleted(context: MessageContext, channel: GroupChannel, messages: List<BaseMessage>) {
                when (context.messagesSendingStatus) {
                    SendingStatus.SUCCEEDED -> {
                        // Remove the sent message from your data source.
                    }
                    SendingStatus.FAILED -> {
                        // Remove the failed message from your data source.
                    }
                }
            }

            override fun onChannelUpdated(context: GroupChannelContext, channel: GroupChannel) {
                // Change the chat view with the updated channel information.
            }

            override fun onChannelDeleted(context: GroupChannelContext, channelUrl: String) {
                // This is called when a channel is deleted. So the current chat view should be cleared.
            }

            override fun onHugeGapDetected() {
                // The Chat SDK detects that more than 300 messages are missing.

                // Clear the collection.
                collection.dispose()

                // Create a new message collection object.
                createMessageCollection()

                // An additional implementation is required for initialization.
            }
        }
    }
)

Loaded messages

Copy link

The MessageCollection holds list of messages that are loaded by initialize(), loadMore(), loadPrevious() or by message events, the succeededMessages. It is recommended to use this list as the datasource of your RecyclerView as this list is the most updated list.

Also, it has pendingMessages and failedMessages which are list of messages that are being sent and messages that have been failed to be sent respectively.

// Loaded messages
val messages = collection.succeededMessages

// Pending messages which are being sent.
// When the message sending is done, either succeed or fail, those messages will be moved to succeededMessages or failedMessages.
val pendingMessages = collection.pendingMessages

// Messages that have been failed to be sent
val failedMessages = collection.failedMessages

In local caching, a gap refers to a chunk of objects that are created and logged on the Sendbird server but missing from the local cache. Depending on the connection status, the client app could miss message events and new messages stored in the Sendbird server may not reach the Chat SDK in the client app. In such cases, a gap is created.

Small gaps can be filled in through changelog sync. However, if the client app has been disconnected for a while, too big of a gap can be created.

Huge gap

Copy link

A gap can be created for many reasons, such as when a user has been offline for days. When the client app comes back online, the Chat SDK checks with the Sendbird server to see if there are any new messages. If it detects that more than 300 messages are missing in the local cache compared to the Sendbird server, the SDK determines that there is a huge gap and onHugeGapDetected() is called.

Note: To adjust the number of missing messages that result in a call for onHugeGapDetected(), contact our support team.

In this case, the existing MessageCollection instance should be cleared through the dispose() method and a new one must be created for better performance.

collection.dispose()

Dispose of the collection

Copy link

The dispose() method should be called when you destroy the chat screen to notify the SDK that this collection is no longer visible.

For example, this should be used when the current user exits from the chat screen by pressing a back key or when a new collection has to be created due to a huge gap detected by onHugeGapDetected().

collection.dispose()