Skip to main content


The SDK is optimized to avoid waste of resources and improve performance. You can freely choose which optimizations should be enabled or disabled.

Multiple Calls to API#

After version 5.3.0, the SDK prevents the user from making multiple calls to the backend. If a call is already running, the SDK merges a new request into the current one and the data is propagated to both requesters of the Call.

You can change the default behavior and force calls to always make new requests to API and never merge two requests into one by using:


If you want to control new requests to API in a more granular way, you can use the extension function:

Call<T>.forceNewRequest(): Call<T>

The returned Call will be forced to make a new request to API.


To sort your object and present then in a desired order, tt is possible to choose between 2 implementations of QuerySorter: QuerySort and QuerySortByField.


QuerySortByField is the default implementation used by the SDK.

QuerySort uses reflection to find the fields used for comparison. This helps you avoid creating an extra comparator implementation to support your's use case.

The drawback is that reflection is an expensive operation and this implementation will have lower performance compared to QuerySortByField.

You can also choose to not use reflection and gain performance by using QuerySortByField instead, but this requires some extra work. Your custom class needs to implement the ComparableFieldProvider interface and provide the names of the fields used to sort the list. Like the example:

public data class Channel(
var cid: String = "",
var id: String = "",
var type: String = "",
var name: String = "",
var image: String = "",
var hiddenMessagesBefore: Date? = null,
val cooldown: Int = 0,
var pinnedMessages: List<Message> = mutableListOf(),
var ownCapabilities: Set<String> = setOf(),
var membership: Member? = null,
override var extraData: MutableMap<String, Any> = mutableMapOf(),
) : CustomObject, ComparableFieldProvider {

* Determines the last updated date/time.
* Returns either [lastMessageAt] or [createdAt].
val lastUpdated: Date?
get() = lastMessageAt?.takeIf { createdAt == null || it.after(createdAt) } ?: createdAt

* Whether a channel contains unread messages or not.
val hasUnread: Boolean
get() = unreadCount?.let { it > 0 } ?: false

override fun getComparableField(fieldName: String): Comparable<*>? {
return when (fieldName) {
"cid" -> cid
"id" -> id
"type" -> type
"name" -> name
"image" -> image
"cooldown" -> cooldown
"lastUpdated" -> lastUpdated
else -> extraData[fieldName] as? Comparable<*>

Models included in the SDK already implement the ComparableFieldProvider interface and include all the fields together with extraData!

Did you find this page helpful?