Исключение не попасть в сопрограммы - PullRequest
3 голосов
/ 22 мая 2019

Я не могу выполнить обработку ошибок в сопрограммах.Я читал много статей и документацию по обработке исключений , но я не могу заставить ее работать.

Вот мои настройки:

Мой ViewModelзапускает сопрограмму с ее областью действия

class MyViewModel(private var myUseCase: MyUseCase) : ViewModel() {
    private val viewModelJob = Job()
    private val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob)

    fun doSomething() {
        uiScope.launch {
            try {
                myUseCase()
            } catch (exception: Exception) {
                // Do error handling here
            }
        }
    }
}

My UseCase просто обрабатывает несколько логику, и в этом случае некоторый валидатор

class MyUseCase(private val myRepository: MyRepository) {
    suspend operator fun invoke() {
        if (checker()) {
            throw CustomException("Checker Failed due to: ...")
        }

        myRepository.doSomething()
    }
}

Тогда мой Repository просто обрабатываетсетевой уровень / локальный уровень

object MyRepository {
    private val api = ... // Retrofit

    suspend fun doSomething() = api.doSomething()
}

А вот мой интерфейс Retrofit

interface MyInterface {
    @POST
    suspend fun doSomething()
}

Try / catch из ViewModel может обработать ошибку при вызове Retrofit, однако может:не поймать ошибку от CustomException, выданного UseCase.Из статей, которые я читал, это должно работать.Если я использую async, я могу сделать await и использовать ошибку, но мне не нужно использовать async в этом случае, и я обдумывал это.Я могу заблудиться.

Любая помощь будет принята с благодарностью!Заранее спасибо!

Редактировать:

Вот журнал ошибок, который я получаю:

com.example.myapp.domain.errors.CustomException
        at com.example.myapp.domain.FeatureOne$invoke$2.invokeSuspend(FeatureOne.kt:34)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:238)
        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594)
        at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:742)

Ошибка прямо указывает на явный оператор throw.

Ответы [ 2 ]

3 голосов
/ 22 мая 2019

Попытка с CoroutineExceptionHandler может быть обходным путем для обработки исключений внутри сопрограмм.

CoroutineExceptionHandler context элемент используется в качестве универсального блока catchсопрограммы, где пользовательская регистрация или исключение может иметь место.Это похоже на использование Thread.uncaughtExceptionHandler.

Как его использовать?

val handler = CoroutineExceptionHandler { _, exception -> 
    println("Caught $exception") 
}
val job = GlobalScope.launch(handler) {
    throw AssertionError()
}
val deferred = GlobalScope.async(handler) {
    throw ArithmeticException() // Nothing will be printed, relying on user to call 
    deferred.await()
}
joinAll(job, deferred)

В вашем ViewModel убедитесь, что ваш uiScope использует SupervisorJob вместо Job.SupervisorJob может справиться со своей детской неудачей индивидуально.Job будет отменено в отличие от SupervisorJob

Если вы используете 2.1.0 для AAC Lifecycle и ViewModel, используйте вместо этого расширение viewModelScope.

0 голосов
/ 22 мая 2019

Насколько я знаю, Retrofit еще не создал способ помечать методы ключевым словом suspend. Вы можете сослаться на эту ссылку . Таким образом, правильный путь вашего MyInterface будет:

interface MyInterface {
    @POST
    fun doSomething(): Deferred<Response<YourDataType>>
}
...