【发布时间】:2019-09-03 11:25:09
【问题描述】:
我想要实现的是在我的 BaseActivity 活动中拥有 UI、IO 和 DEFAULT CoroutineScope。然后将这些作用域用于一些操作。
除非在suspendCoroutine {}中抛出异常,否则一切似乎都正常。
如果没有抛出异常,我可以多次使用 ioScope 而不会出现问题。但是如果在 Response.ErrorListener 中抛出异常并且我调用 loginAsync(),async 将不会被执行,协程会卡在 userDeferred.await()。
我检查了 ioScope.isActive 标志。在抛出异常之前标志设置为真。抛出异常后标志设置为false,我可以在范围内抛出异常。
我发现当我使用 withContext(ioScope.coroutineContext){} 代替 ioScope.async{ } 函数时,异常不会破坏作用域并且可以再次使用。
谁能帮我解决这个问题。我在文档和博客中都找不到任何帮助。
基础活动 CoroutineScopes 创建。
abstract class BaseActivity : AppCompatActivity() {
private val ioJob = Job()
private val defaultJob = Job()
private val uiJob = Job()
protected val ioScope: CoroutineScope
get() = CoroutineScope(Dispatchers.IO + ioJob)
protected val uiScope: CoroutineScope
get() = CoroutineScope(Dispatchers.Main + uiJob)
protected val defaultScope: CoroutineScope
get() = CoroutineScope(Dispatchers.Default + defaultJob)
final override fun finish() {
super.finish()
uiJob.cancel()
defaultJob.cancel()
ioJob.cancel()
getActivityTransitions().setFinishActivityTransition(this)
}
}
用户存储库 BaseActivity 中 ioScope 的使用。
@Throws(LoginException::class)
suspend fun loginAsync(loginData: LoginData, context: Context): Deferred<User> {
return ioScope.async {
suspendCoroutine<User> { continuation ->
val jsonObjectRequest = HttpClient.createJsonObjectRequest(
"/users/me2",
loginData.toJsonString(),
Response.Listener {
val httpResponse : HttpResponse<User> = it.toString().jsonToObject()
continuation.resume(httpResponse.response)
},
Response.ErrorListener {
continuation.resumeWithException(LoginException(it))
}
)
HttpClient.getInstance(context).addToRequestQueue(jsonObjectRequest)
}
}
}
登录活动
private suspend fun performLogin() {
val loginData = LoginData(login_username_text_input.value.toString(), login_password_text_input.value.toString())
val userDeferred = UserServerRepository(ioScope).loginAsync(loginData,this@LoginActivity);
try {
val result = userDeferred.await()
login_username_text_input.value = result.company
//HomeActivity.startActivity(this@LoginActivity)
//finish()
}catch (loginException: LoginException){
login_username_text_input.value = loginException.message
}
}
LoginActivity 按钮设置
loginButton.main_button.setAsyncSafeOnClickListener(uiScope, suspend {
performLogin()
})
setAsyncSafeOnClickListener 实现
fun View.setAsyncSafeOnClickListener(uiScope: CoroutineScope, action: suspend () -> Unit) {
val safeClickListener = SafeClickListener {
uiScope.launch {
isEnabled = false
action()
isEnabled = true
}
}
setOnClickListener(safeClickListener)
}
【问题讨论】:
标签: kotlin async-await coroutine