在主屏幕上,有3个异步请求:
viewModelScope.launch {
try {
val requestAccountDeffer = async { requestAccounts() }
val updateStatusDeffer = async { updateVerificationStatus() }
val requestProfileDeffer = async { requestProfile() }
requestAccountDeffer.await()
updateStatusDeffer.await()
requestProfileDeffer.await()
} catch (exception: Throwable) {
// ...
}
}
我的后端使用一个将过期一分钟的accessToken和一个updateToken来对其进行更新。在每个请求之前,都会检查accessToken是否已过期,并在必要时进行更新。
问题在于,如果accessToken在主屏幕开始处过期,则更新它的方法将被调用3次(在每个异步{...}块中),并且后端将在以下情况下返回错误:尝试更新accessToken。如何仅进行一次asynс块调用来更新令牌?
我可以在调用异步块之前同步更新令牌,但是在我看来,这不是完全正确的解决方案。
更新
当前accessToken和refreshToken存储在sharefPrefs中。
答案 0 :(得分:1)
您可以通过使用Kotlin的异步Mutex
来避免同时更新共享资源(在这种情况下为访问令牌):
interface Mutex
(Mutex.kt
)协程互斥。
kotlinx-coroutines-core / kotlinx.coroutines.sync / Mutex
基本上,您可以锁定资源,必要时将其挂起,检查它是否已过期并可能更新,然后返回当前值。
private lateinit var currentToken: AccessToken
private val tokenMutex = Mutex()
suspend fun getToken(): AccessToken {
return tokenMutex.withLock {
if (currentToken.isExpired) {
// Refresh token
val newToken = ...
// Update the stored token
currentToken = newToken
newToken
} else currentToken
}
}
然后,而不是直接访问当前令牌值,而是使用此函数作为一种获取或更新代理。
Mutex
的功能与Lock
相同,除了它是挂起而不是阻塞并且是不可重入的。
也就是说,我认为在发出三个请求之前更新令牌的替代方法不会有什么问题。
旁注:绝对没有理由启动三个Deferred
工作并立即等待它们;这是coroutine scopes的非常好的用例:
coroutineScope {
launch { requestAccounts() }
launch { updateVerificationStatus() }
launch { requestProfile() }
}
此调用将暂停,直到所有新创建的作用域的子作业完成为止,并且一旦其中一个子项引发异常,该调用就会失败。
如果这种行为不是您想要的,则可以使用SupervisorScope
(另请参见When to use coroutineScope
vs supervisorScope
?),或安装自己的异常处理程序。