Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,14 +181,15 @@ fun onSendRequest() {
}
```

Also you can add some custom `catch` handlers for `ExceptionHandler`:
Also you can add some custom `catch` handlers for `ExceptionHandler` that work as a catch in the
try/catch operator:

```kotlin
fun onSendRequest() {
viewModelScope.launch {
exceptionHandler.handle {
serverRequest()
}.catch<IllegalArgumentException> { // Specifying a specific exception class
}.catch<IllegalArgumentException> { // Specifying exception class
// Some custom handler code
false // true - cancels ErrorPresenter; false - allows execution of ErrorsPresenter
}.execute() // Starts code execution in `handle` lambda
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,22 @@ package dev.icerock.moko.errors.handler
import dev.icerock.moko.errors.ErrorEventListener
import dev.icerock.moko.errors.HandlerResult
import dev.icerock.moko.mvvm.dispatcher.EventsDispatcher
import kotlin.reflect.KClass

abstract class ExceptionHandlerContext<R> {
abstract suspend fun execute(): HandlerResult<R, Throwable>
abstract fun <E : Throwable> catch(
clazz: KClass<E>,
condition: (Throwable) -> Boolean,
catcher: (E) -> Boolean
): ExceptionHandlerContext<R>
abstract fun finally(block: () -> Unit): ExceptionHandlerContext<R>

inline fun <reified E : Throwable> catch(
noinline catcher: (E) -> Boolean
): ExceptionHandlerContext<R> {
return catch(E::class, catcher)
return catch(
condition = { it is E },
catcher = catcher
)
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import dev.icerock.moko.errors.ErrorEventListener
import dev.icerock.moko.errors.HandlerResult
import dev.icerock.moko.mvvm.dispatcher.EventsDispatcher
import kotlinx.coroutines.CancellationException
import kotlin.reflect.KClass

private typealias Catcher = (Throwable) -> Boolean

Expand All @@ -18,15 +17,16 @@ internal class ExceptionHandlerContextImpl<T : Any, R>(
private val onCatch: ((Throwable) -> Unit)?,
private val block: suspend () -> R
) : ExceptionHandlerContext<R>() {
private val catchersMap = mutableMapOf<KClass<*>, Catcher>()
private val catchers = mutableListOf<Pair<(Throwable) -> Boolean, Catcher>>()

private var finallyBlock: (() -> Unit)? = null

@Suppress("UNCHECKED_CAST")
override fun <E : Throwable> catch(
clazz: KClass<E>,
condition: (Throwable) -> Boolean,
catcher: (E) -> Boolean
): ExceptionHandlerContext<R> {
catchersMap[clazz] = catcher as Catcher
catchers.add(condition to catcher as Catcher)
return this
}

Expand All @@ -43,8 +43,8 @@ internal class ExceptionHandlerContextImpl<T : Any, R>(
// Don't handle coroutines CancellationException
if (e is CancellationException) throw e
onCatch?.invoke(e)
val isHandled = catchersMap[e::class]?.invoke(e)
if (isHandled == null || isHandled == false) {
val isHandled = isHandledByCustomCatcher(e)
if (!isHandled) { // If not handled by a custom catcher
val errorValue = exceptionMapper(e)
eventsDispatcher.dispatchEvent {
showError(e, errorValue)
Expand All @@ -55,4 +55,11 @@ internal class ExceptionHandlerContextImpl<T : Any, R>(
finallyBlock?.invoke()
}
}

private fun isHandledByCustomCatcher(cause: Throwable): Boolean {
return catchers
.firstOrNull { it.first.invoke(cause) } // Finds custom catcher by invoking conditions
?.second?.invoke(cause) // If catcher was found then execute it
?: false
}
}