【问题标题】:How can I refactor this Kotlin method with coroutines properly firing off?如何使用协程正确启动来重构这个 Kotlin 方法?
【发布时间】:2021-12-31 01:46:03
【问题描述】:

采取这种方法

override suspend fun login(email: String, password: String): BaseResult<Unit> {
    coroutineScope {
        try {
            fetchMobileConfig()
        } catch (e: Exception) {
            // Unhandled because it seems like a fire and forget.
        }
    }
    

    val loginRequest = LoginRequest(
        email = email,
        password = password
    )

    return when (val response = loginNetwork.login(loginRequest)) {
        is NetworkResponse.Success -> {
            coroutineScope {
                launch {
                    getUserData()
                }
            }

            callSomeFinishingFunctionThatIsSuspending()

            BaseResult.Ok(Unit)
        }
        is NetworkResponse.Error.Unauthorised -> {
            BaseResult.Error(response.exception)
        }
    }
}

我遇到了这个方法,想重构一下。我有一些想法,但想看看有没有更好的东西我没有考虑过。它实际上似乎有效,但感觉有点混乱。

从带有 viewModelScope{} 的 ViewModel 调用该方法。

fetchMobileConfig() 和 getUserData() 函数有点奇怪,但它们目前似乎是“一劳永逸”的方法。基本上如果他们失败了,登录应该不会失败。

返回的 BaseResult 用于通知 ViewModel 状态。如果你好奇loginNetwork中login方法是怎么调用的,看起来是这样的:

override suspend fun login(loginRequest: LoginRequest): NetworkResponse<SessionToken> {
        return performRequest {
            loginService.login(loginRequest)
        }
    }

我对目前的工作方式感到满意。

在顶部编写此存储库级别函数的更好方法是什么?我对另一种结构持开放态度。

【问题讨论】:

    标签: android kotlin kotlin-coroutines


    【解决方案1】:

    coroutineScope { } 函数如果您在其中启动的协程少于两个,则毫无意义,因此您可以在不改变功能的情况下删除对它的两种使用。在第二种情况下,您启动单个协程,您也可以删除内部的launch,以便等待挂起函数调用的结果。

    如果你想让你的协程在 getUserData() 失败的情况下继续运行,你也应该将它包裹在 runCatching 中。在您当前的代码中,coroutineScope 块将重新抛出您启动的子协程中遇到的任何异常。

    如果你使用 try/catch 而不使用返回值或在 catch 块中做任何事情,你可以使用 runCatching 来简洁。

    当您传递的变量已经具有匹配的名称时,使用命名参数是一种不必要的冗长。

    以上改动给出:

    override suspend fun login(email: String, password: String): BaseResult<Unit> {
        runCatching { 
            fetchMobileConfig()
        }
    
        val loginRequest = LoginRequest(email, password)
    
        return when (val response = loginNetwork.login(loginRequest)) {
            is NetworkResponse.Success -> {
                runCatching {
                    getUserData()
                }
                callSomeFinishingFunctionThatIsSuspending()
                BaseResult.Ok(Unit)
            }
            is NetworkResponse.Error.Unauthorised -> {
                BaseResult.Error(response.exception)
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-04-17
      • 2020-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-06-29
      • 2020-07-15
      • 1970-01-01
      相关资源
      最近更新 更多