Сопрограмма Kotlin немедленно выдает исключение, если последняя операция завершилась с исключением

Когда я пытался войти в свой сервис через дооснащение. Когда моя служба отключена, через 10 секунд после нажатия кнопки я получил исключение SocketTimeoutException. Пока все нормально, но я снова нажал кнопку после того, как ошибка сразу же выдала ту же ошибку. Что случилось?

interface LoginService {

    @FormUrlEncoded
    @POST("/login")
    fun login(@Field("id") id: String, @Field("pw") pw: String): Deferred<Response<User>>

}

class LoginViewModel : ViewModel() {

    private var job: Job = Job()
    private val scope: CoroutineScope = CoroutineScope(Dispatchers.Main + job)
    private val service by lazy { RetrofitApiFactory().create(LoginService::class.java) }
    private val excHandler = CoroutineExceptionHandler { _, throwable ->
        Timber.e(throwable);
    }

    fun doLogin(id: String, pw: String) {
        scope.launch(excHandler) {
            val response = service.login(id, pw).await()
            if (response.isSuccessful) {
                response.body()
                        ?.let { user -> doOnSuccess(user) }
                        ?: doOnError(InvalidUserException())
            } else doOnError(Exception())
        }
    }

    private fun CoroutineScope.doOnError(e: Throwable) {
        excHandler.handleException(coroutineContext, e)
    }

    private fun doOnSuccess(user: User) {
        ...
    }

    override fun onCleared() {
        job.cancel()
    }

}

Я вижу большую проблему в этом дизайне, у него есть несколько каналов для сообщения об ошибке. Сначала идет Response, который может быть успешным или нет, затем Deferred, который может быть завершен или отменен. В хорошем дизайне вместо Deferred будет suspend fun, и он будет сигнализировать обо всех ошибках через исключения. Если вы получили ответ, значит, он успешен.

Marko Topolnik 15.10.2018 09:21

См. здесь для подробного объяснения философии, лежащей в основе suspend fun по сравнению с Deferred.

Marko Topolnik 15.10.2018 09:26

Без Deferred пользоваться не могу. Выдает ошибку: java.lang.IllegalArgumentException: Unable to create call adapter for retrofit2.Response

kibar 15.10.2018 21:46

Да, насколько мне известно, Retrofit поддерживает только Deferred, но я думаю, что он также должен поддерживать suspend fun. Вы заявили о своей функции как suspend fun?

Marko Topolnik 15.10.2018 21:55
Здесь, поддержка suspend fun появится, как только выйдет Kotlin 1.3.
Marko Topolnik 15.10.2018 21:56
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
5
344
1

Ответы 1

Вам необходимо изменить свой CoroutineScope, чтобы не использовать повторно тот же Job. Он уже считается не смогли, поэтому даже не начнет выполняться.

См. связанная проблема на github.

Этот совет фатально неверен, он устраняет причину, по которой основная работа существует в первую очередь. Лучший совет - не позволяйте исключению уйти без обработки. Если это не вариант, воспользуйтесь советом из проблемы GitHub и используйте SupervisorJob вместо Job.

Marko Topolnik 15.10.2018 09:14

Другие вопросы по теме