Когда я пытался войти в свой сервис через дооснащение. Когда моя служба отключена, через 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()
}
}
См. здесь для подробного объяснения философии, лежащей в основе suspend fun
по сравнению с Deferred
.
Без Deferred
пользоваться не могу. Выдает ошибку: java.lang.IllegalArgumentException: Unable to create call adapter for retrofit2.Response
Да, насколько мне известно, Retrofit поддерживает только Deferred
, но я думаю, что он также должен поддерживать suspend fun
. Вы заявили о своей функции как suspend fun
?
Вам необходимо изменить свой CoroutineScope
, чтобы не использовать повторно тот же Job
. Он уже считается не смогли, поэтому даже не начнет выполняться.
См. связанная проблема на github.
Этот совет фатально неверен, он устраняет причину, по которой основная работа существует в первую очередь. Лучший совет - не позволяйте исключению уйти без обработки. Если это не вариант, воспользуйтесь советом из проблемы GitHub и используйте SupervisorJob
вместо Job
.
Я вижу большую проблему в этом дизайне, у него есть несколько каналов для сообщения об ошибке. Сначала идет
Response
, который может быть успешным или нет, затемDeferred
, который может быть завершен или отменен. В хорошем дизайне вместоDeferred
будетsuspend fun
, и он будет сигнализировать обо всех ошибках через исключения. Если вы получили ответ, значит, он успешен.