【发布时间】:2018-10-14 16:04:17
【问题描述】:
当我尝试通过改造登录我的服务时。当我的服务关闭时,单击按钮 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,它会通过异常发出所有错误的信号。如果您得到响应,则表示成功。 -
请参阅 here 以全面了解
suspend fun与Deferred背后的理念。 -
如果没有
Deferred,我将无法使用。它给出一个错误:java.lang.IllegalArgumentException: Unable to create call adapter for retrofit2.Response -
是的,据我所知,Retrofit 只支持
Deferred,但我认为它也应该支持suspend fun。您是否将您的函数声明为suspend fun? -
Here,
suspend fun支持将在 Kotlin 1.3 发布后立即发布。