Android 在多个异步协同路由中调用的方法如何只能调用一次?

Android 在多个异步协同路由中调用的方法如何只能调用一次?,android,kotlin,kotlin-coroutines,Android,Kotlin,Kotlin Coroutines,在主屏幕上,有3个异步请求: viewModelScope.launch { try { val requestAccountDeffer = async { requestAccounts() } val updateStatusDeffer = async { updateVerificationStatus() } val requestProfileDeffer = async { requestProfile() } requestAccountDe

在主屏幕上,有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在主屏幕开始时过期,那么更新它的方法将被调用三次(在每个异步{…}块中),并且后端在尝试更新accessToken时将返回错误。如何只进行一次asynСblock调用来更新令牌

我可以在调用异步块之前同步更新令牌,但在我看来,这并不是正确的解决方案

更新

当前accessToken和refreshToken存储在sharefPrefs中

  • 在启动改装请求之前,请检查令牌是否已过期
  • 如果它过期了,那么调用改造方法来更新令牌,我会得到一个响应
  • 在sharefPrefs中保存新令牌
  • 使用更新的访问令牌执行主请求

  • 通过使用Kotlin的异步:

    接口互斥体
    ()

    共程互斥。
    //

    基本上,您可以锁定资源,必要时暂停,检查资源是否已过期并可能续订,然后返回当前值

    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
        }
    }
    
    然后,不直接访问当前令牌值,而是将此函数用作一种get或update代理

    Mutex
    的功能等同于,只是它挂起而不是阻塞,并且不可重入


    也就是说,我认为在发出三个请求之前更新令牌的替代方法不会有任何问题


    旁注:绝对没有理由启动三个
    延迟的
    作业并立即等待它们;这是一个非常好的用例:

    此调用将挂起,直到新创建的作用域的所有子作业完成,并且在其中一个子作业引发异常时将失败


    如果此行为不是您想要的,您可以改用(另请参阅),或安装自己的异常处理程序。

    如果我理解正确,您会担心如果访问令牌在三个请求发出之前过期,那么每个请求都会尝试独立更新访问令牌。您如何在协同程序之间共享/更新当前令牌?理想情况下,多个协同路由不可能同时更新共享资源。如果您想阻止所有请求独立访问或修改当前令牌,您可能必须将访问逻辑封装在某种并发限制机制中,例如锁(无论令牌是存储在内存中还是通过
    SharedReferences
    存储在磁盘上,其基本思想都是相同的)
    coroutineScope {
        launch { requestAccounts() }
        launch { updateVerificationStatus() }
        launch { requestProfile() }
    }