我对协程是陌生的,我想要实现的是在BaseActivity活动中包含UI,IO和DEFAULT CoroutineScope。然后将这些范围用于某些操作。
除非在suspendCoroutine {}中引发异常,否则一切似乎都可以正常工作。
如果没有异常,我可以多次使用ioScope,而不会出现任何问题。但是,如果在Response.ErrorListener中引发异常,并且我调用loginAsync(),异步将不会执行,协程将停留在userDeferred.await()。
我检查了ioScope.isActive标志。在抛出Exception之前,将标志设置为true。抛出异常后,将标记设置为false,我可以在范围内抛出异常。
我发现,当我使用ioScope.async {}函数代替context(ioScope.coroutineContext){}时,异常不会破坏范围,可以再次使用。
任何人都可以帮助我解决此问题。在文档或博客中找不到任何帮助。
BaseActivity 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)
}
}
}
LoginActivity
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)
}
答案 0 :(得分:1)
简短的回答:如果您要拥有强大的范围,则必须使用SupervisorJob()
而不是Job()
。
长答案:这是一篇很棒的文章,介绍了协程作用域中的错误处理如何工作https://proandroiddev.com/kotlin-coroutine-job-hierarchy-finish-cancel-and-fail-2d3d42a768a9