Делегаты и слушатели событий
Для реакции на события SDK у интегратора есть два механизма:
ChatCenterUIListener— интерфейс с 4 callback-методами: счётчик непрочитанных, сетевая ошибка, клик по ссылке, внутреннее исключение SDK. Достаточно для большинства интеграций.ChatUpdateProcessor—SharedFlow-шина для событий уровня доставки сообщений, изменения статусов и состояния соединения. Используется только при построении кастомного UI поверх SDK.
ChatCenterUIListener
fun setChatCenterUIListener(listener: ChatCenterUIListener)
Подписывает приложение на события UI и базовые SDK-события. Вызывать после init(...) — иначе SDK выбросит IllegalStateException. Повторный вызов заменяет предыдущий listener (старые подписки на потоки внутри SDK отменяются).
Методы интерфейса
| Метод | Параметр | Когда вызывается |
|---|---|---|
unreadMessageCountChanged(count: UInt) | количество непрочитанных | Сразу после setChatCenterUIListener(...) (текущее значение), затем при изменении счётчика — authorize(...), получение нового входящего сообщения, прочтение оператором |
networkErrorReceived(error: Error) | edna.chatcenter.core.main.Error — поля и пример обработки см. в Ошибки → networkErrorReceived | Сетевая ошибка от сервера или WebSocket |
urlClicked(url: String) | URL | Пользователь нажал на ссылку в сообщении |
exceptionReceived(trace: String) | стек-трейс | Внутреннее исключение SDK (для логирования) |
Пример
import android.content.Intent
import edna.chatcenter.core.main.ChatCenterUIListener
import edna.chatcenter.core.main.Error // важно: затеняет kotlin.Error — при необходимости используйте alias `as SdkError`
private const val APP_UNREAD_COUNT_BROADCAST = "com.example.app.UNREAD_COUNT"
private const val UNREAD_COUNT_KEY = "unread_count"
chatCenterUI.setChatCenterUIListener(object : ChatCenterUIListener {
override fun unreadMessageCountChanged(count: UInt) {
val intent = Intent(APP_UNREAD_COUNT_BROADCAST)
.putExtra(UNREAD_COUNT_KEY, count.toInt())
applicationContext.sendBroadcast(intent)
}
override fun networkErrorReceived(error: Error) {
Log.e("ChatCenter", "Сетевая ошибка [${error.code}]: ${error.message}")
}
override fun urlClicked(url: String) {
Log.i("UrlClicked", url)
}
})
Потоки callback'ов
| Callback | Поток |
|---|---|
unreadMessageCountChanged | main — можно обновлять UI напрямую |
exceptionReceived | main |
urlClicked | main (приходит из обработчика клика по ссылке в UI) |
networkErrorReceived | фоновый (OkHttp / Retrofit / @WorkerThread-источники) — для UI переключайтесь на main явно |
Рекомендуемый идиом для networkErrorReceived, когда нужно тронуть UI:
override fun networkErrorReceived(error: Error) {
// Этот callback приходит с сетевого потока, не с main.
// Используйте lifecycleScope / viewModelScope вашего экрана.
lifecycleScope.launch(Dispatchers.Main) {
showErrorToUser(error)
}
}
Для View-based кода вне coroutine-контекста допустимы view.post { ... } или Handler(Looper.getMainLooper()).post { ... } — но если в проекте уже используются корутины, держитесь одного идиома (Dispatchers.Main).
Подробное обоснование (где и почему вызывается callback) с конкретными call-sites — в Известных ограничениях.
Продвинутые сценарии
Раздел ниже нужен только если вы строите собственный список сообщений / индикаторы статусов поверх SDK или мониторите события SDK на низком уровне. Для бейджа непрочитанных, сетевых ошибок и кликов по ссылкам достаточно ChatCenterUIListener выше.
Подписка на дополнительные события — ChatUpdateProcessor
Если в вашем сценарии нужны события, которых нет в ChatCenterUIListener (например, точный момент доставки сообщения на сервер или сигнал закрытия офлайн-сокета), доступна реактивная шина ChatUpdateProcessor из пакета edna.chatcenter.core.chatUpdates. Класс предоставляет публичные MutableSharedFlow-потоки. Ниже описаны 6 базовых для кастомного UI; помимо них в классе есть потоки для quick replies, typing-индикатора, обновления вложений и прогресса загрузки файлов — доступны как поля того же класса, см. KDoc исходников.
| Поток | Что эмитится | Когда полезно |
|---|---|---|
newMessageFlow | ChatItem — элемент истории чата, добавленный после ответа сервера (включая исходящие, пришедшие в GET_MESSAGES) | Кастомное оповещение/счётчик помимо штатного push'а |
messageSendSuccessFlow | ChatItemProviderData (uuid, messageId, sentAt) — подтверждение от сервера, что исходящее сообщение принято | Подтверждение доставки на стороне приложения |
messageSendErrorFlow | ChatItemSendErrorModel | Реакция на ошибку отправки (retry-стратегия) |
outgoingMessageStatusChangedFlow | List<Status> — пачка обновлений статусов (Status.status принимает значение MessageStatus); в одном эмитте — статусы разных сообщений | Отображение «галочек» в кастомном UI |
socketIsClosedFlow | Int — код закрытия WebSocket | Индикатор офлайн-режима |
cleanAllOnUiFlow | Сигнал на очистку UI | Сброс кастомного состояния — эмитится в обоих сценариях logout() (как при отложенной очистке во время хендшейка, так и при полной) |
Получить экземпляр — через inject()-делегат публичного DI-контейнера SDK:
import edna.chatcenter.core.chatUpdates.ChatUpdateProcessor
import edna.chatcenter.core.serviceLocator.core.inject
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
val processor: ChatUpdateProcessor by inject()
// ChatUpdateProcessor эмитит из Dispatchers.Unconfined — события приходят не на Main
// thread (на потоке, где сработал emit() внутри SDK). Перед UI-вызовами оборачивайте
// код в withContext(Dispatchers.Main). Подробности — в Известных ограничениях.
lifecycleScope.launch {
processor.newMessageFlow.collect { item ->
withContext(Dispatchers.Main) {
// обновление UI
}
}
}
inject() — публичный DI-контейнер SDK, не Hilt/KoinДелегат inject() принадлежит публичному пакету edna.chatcenter.core.serviceLocator.core и не связан с DI-фреймворками вашего приложения (Hilt, Koin, Dagger).
Дополнительные модели для кастомного UI
Этими типами вы можете оперировать при построении собственного интерфейса чата (списка сообщений, индикаторов статусов, прогресса скачивания файлов). Создавать их экземпляры вручную не нужно — SDK эмитит их сам через ChatUpdateProcessor или передаёт в callback'ах.
FileDescription — модель вложения
edna.chatcenter.core.models.FileDescription — модель файлового вложения, которую SDK эмитит для элементов истории чата (исходящие сообщения хранят список как UserPhrase.files, входящие — аналогично).
Ключевые поля: fileUri: Uri?, size: Long, from: String?, state: MutableStateFlow<AttachmentStateEnum> (default ANY; SDK обновляет сам — читайте через state.value / state.collect { ... }, не модифицируйте), errorCode: ErrorStateEnum (default ANY), downloadPath: String?.
AttachmentStateEnum (ANY, PENDING, ERROR, EXPIRED, READY) и ErrorStateEnum — публичные enum'ы из того же пакета (edna.chatcenter.core.models.enums).
ProgressReceiver — события скачивания файлов
edna.chatcenter.core.broadcastReceivers.ProgressReceiver — BroadcastReceiver, через который SDK сообщает о ходе скачивания файлов. Регистрируйте, если нужно отображать собственный индикатор прогресса. Константы actions объявлены в companion object самого ProgressReceiver:
ProgressReceiver.PROGRESS_BROADCAST— обновление прогресса (0..100).ProgressReceiver.DOWNLOADED_SUCCESSFULLY_BROADCAST— файл скачан.ProgressReceiver.DOWNLOAD_ERROR_BROADCAST— ошибка скачивания.
Intent содержит FileDescription как Parcelable-extra под ключом FileDownloadWorker.FD_TAG (edna.chatcenter.core.workers.FileDownloadWorker.FD_TAG). Для DOWNLOAD_ERROR_BROADCAST дополнительно передаётся Throwable через Serializable-extra под ключом ProgressReceiver.DOWNLOAD_ERROR_BROADCAST (та же константа используется и в качестве action).
MessageStatus — enum статусов сообщения
Описан в каноническом разделе Сообщения → Статусы сообщения. Используется для построения кастомных индикаторов «галочек» (поле sentState отправленных элементов истории).
Связанные разделы
- Сообщения (messages) —
send(),prefill(), счётчик непрочитанных. - Ошибки (errors) — обработка
ErrorизnetworkErrorReceived. - Известные ограничения — нюансы coroutine-scopes продвинутой шины событий.