android - 多个异步协程中调用的方法怎么只调用一次呢?
问题描述
在主屏幕上,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,它会过期一分钟,并使用一个 refreshToken 来更新它。在每次请求之前,都会检查 accessToken 以查看它是否已过期并在必要时进行更新。
问题是如果 accessToken 在主屏幕开始时过期,那么更新它的方法将被调用 3 次(在每个 async {...} 块中),并且后端在尝试更新时会返回错误访问令牌。如何使只有一个异步块调用来更新令牌?
我可以在调用异步块之前同步更新令牌,但在我看来这不是正确的解决方案。
更新
当前 accessToken 和 refreshToken 存储在 sharefPrefs 中。
- 在开始改造请求之前,请检查令牌是否已过期。
- 如果它已过期,则调用改造方法来更新令牌,我会得到响应。
- 在 sharefPrefs 中保存新令牌。
- 使用更新的访问令牌执行主请求。
解决方案
您可以使用 Kotlin 的 asynchronous 避免并发更新共享资源(在本例中为访问令牌)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
工作并立即等待它们;这是协程作用域的一个很好的用例:
coroutineScope {
launch { requestAccounts() }
launch { updateVerificationStatus() }
launch { requestProfile() }
}
此调用将暂停,直到新创建范围的所有子作业都完成,并且一旦其中一个子作业抛出异常就会失败。
如果此行为不是您想要的,您可以使用 aSupervisorScope
代替(另请参阅何时使用coroutineScope
vs supervisorScope
?),或安装您自己的异常处理程序。
推荐阅读
- javascript - RXJS。每隔几秒从媒体流中获取价值
- r - R和ggplot中从右到左的语言
- c++ - 如何使用 C++ 实现并发文件/文本编辑?
- python - 如果列表包含任何列表返回匹配字符串
- javascript - 如何使用 javascript 将引导警报动态添加到页面?
- javascript - 从自定义 React 组件库导入和使用组件会导致 Invariant Violation: Invalid hook call
- python - numpy 数组的 [::-1] 切片是什么?
- pandas - 在数据框图中显示符号名称
- python - 坚持将多对多关系与 Modelform 联系起来
- html - Nativescript/angular listpicker 不显示数组列表