Skip to main content

moko-errors

Библиотека moko-errors позволяет обрабатывать и показывать ошибки на экране из общего кода.

ExceptionMappersStorage

ExceptionMappersStorage — синглтон, хранящий набор конвертеров исключений в классы ошибок, требуемые ErrorPresenter.

Регистрация простого маппера:

ExceptionMappersStorage
.register<IllegalArgumentException, StringDesc> {
"Был передан недопустимый аргумент!".desc()
}
.register<HttpException, Int> {
it.code
}

Регистрация маппера с условием:

ExceptionMappersStorage.condition<StringDesc>(
condition = { it is CustomException && it.code == 10 },
mapper = { "Произошла кастомная ошибка!".desc() }
)

Для каждого типа ошибки (кроме StringDesc, у которого уже есть значение по умолчанию) необходимо задать fallback-значение через setFallbackValue:

ExceptionMappersStorage
.setFallbackValue<Int>(520)

val throwableToIntMapper: (Throwable) -> Int =
ExceptionMappersStorage.throwableMapper()

Регистрацию можно выстраивать в цепочку:

ExceptionMappersStorage
.condition<StringDesc>(
condition = { it is CustomException && it.code == 10 },
mapper = { "Произошла кастомная ошибка!".desc() }
)
.register<IllegalArgumentException, StringDesc> {
"Был передан недопустимый аргумент!".desc()
}
.register<HttpException, Int> {
it.code
}
.setFallbackValue<Int>(520)

ExceptionHandler

ExceptionHandler реализует безопасное выполнение кода и автоматическое отображение ошибок через ErrorPresenter.

Объявление в ViewModel:

class SimpleViewModel(
val exceptionHandler: ExceptionHandler
) : ViewModel()

Привязка на платформе.

На Android в Activity или Fragment:

viewModel.exceptionHandler.bind(
lifecycleOwner = this,
activity = this
)

На iOS в ViewController:

viewModel.exceptionHandler.bind(viewController: self)

Создание экземпляра ExceptionHandler:

val exceptionHandler = ExceptionHandler<StringDesc>(
errorPresenter = errorPresenter,
exceptionMapper = ExceptionMappersStorage.throwableMapper(),
onCatch = { println("Поймано исключение: $it") }
)

Использование в ViewModel:

fun onSendRequest() {
viewModelScope.launch {
exceptionHandler.handle {
serverRequest()
}.finally {
// код после выполнения
}.execute()
}
}

Можно добавлять кастомные catch-обработчики:

fun onSendRequest() {
viewModelScope.launch {
exceptionHandler.handle {
serverRequest()
}.catch<IllegalArgumentException> {
// кастомная обработка
false // true — отменяет показ ошибки; false — позволяет ErrorPresenter показать ошибку
}.execute()
}
}

ErrorPresenter

Набор реализаций ErrorPresenter, определяющих способ отображения ошибки на платформе:

  • AlertErrorPresenter — показывает ошибку в alert-диалоге;
  • ToastErrorPresenter — показывает ошибку в toast на Android (на iOS — alert-диалог);
  • SnackBarErrorPresenter — показывает ошибку в snackbar на Android (на iOS — alert-диалог);
  • SelectorErrorPresenter — выбирает презентер по условию.

Создание презентеров в общем коде:

val alertErrorPresenter = AlertErrorPresenter(
alertTitle = "Ошибка".desc(),
positiveButtonText = "OK".desc()
)
val toastErrorPresenter = ToastErrorPresenter(
duration = ToastDuration.LONG
)

SelectorErrorPresenter позволяет выбрать способ показа в зависимости от типа исключения:

val selectorErrorPresenter = SelectorErrorPresenter { throwable ->
when (throwable) {
is CustomException -> alertErrorPresenter
else -> toastErrorPresenter
}
}

val exceptionHandler = ExceptionHandler(
errorPresenter = selectorErrorPresenter,
exceptionMapper = ExceptionMappersStorage.throwableMapper()
)

Дополнительные материалы