【问题标题】:kotlin - run sequentially flowskotlin - 顺序运行流程
【发布时间】:2021-06-09 16:56:44
【问题描述】:

我有以下功能:

fun validateEmail(email: String) = flowOf {
    when {
        email.isEmpty() -> throw EmailError.Empty
        email.contains("@") -> email
        else -> throw EmailError.NotValid
    }
}
fun validatePassword(password: String) = flowOf {
    when {
        password.isEmpty() -> throw PasswordError.Empty
        else -> password
    }
}

fun useCaseLogin(email: String, password: String) = flow {
    //response: MyResponse = make and http request
    emit(response)
}

然后我想知道是否可以通过以下方式运行此流程:

fun login(email: String, password: String) = 
    validateEmail(email).then(validatePassword(password))
                        .then(useCaseLogin(email, password)) { response: MyResponse -> 
        if (response==200) {
           emit("Login success!!")
        } else {
           emit("Login failed")
        }
 }.catch { e: Throwable ->
  when (e) {
    is EmailError.NotValid -> {
        print(e.localizedMessage)
    }
    is EmailError.Empty -> {
        print(e.localizedMessage)
    }
    is PasswordError.Empty -> {
        print(e.localizedMessage)
    }
  }
}.asLiveData(viewModelScope.coroutineContext)

有没有办法写出这样的东西?

【问题讨论】:

  • 为什么验证函数会返回 Flows?似乎添加了没有任何好处的卷积。
  • 这些看起来应该只是挂起函数,而不是流。
  • 我认为它们甚至不应该是挂起函数,因为它们会在微不足道的工作中立即返回。
  • @Tenfour04 是的,这是一个很好的观点。由于验证功能正在处理琐碎的工作,我同意,它们不应该是一个流程。我怎么能改变它?

标签: kotlin kotlin-coroutines kotlin-flow


【解决方案1】:

您正在寻找的是combine 运算符:

val emailFlow = validateEmail(email)
val pwdFlow = validatePassword(pwd)

emailFlow
    .combine(pwdFlow) { email, pass -> Pair(email, pass) }
    // In case your useCaseLogin is just a suspending function
    .map { (email, pass) ->
        val result = useCaseLogin(email, pass)
    }
    // In case your useCaseLogin returns a Flow with some result
    .flatMap { (email, pass) -> useCaseLogin(email, pass) }

虽然 cmets 是正确的,但将验证设置为 Flow 有点矫枉过正。您可以构建一个可为空的错误Flow,您可以使用它来映射到 UI 并在每个字段下方显示一个小标签。

我会这样处理:

class YourViewModel() : ViewModel() {
     val emailFlow = MutableStateFlow("");
     val passwFlow = MutableStateFlow("");

     val emailError = emailFlow.map { validateEmail(it) }
     val passwError = emailFlow.map { validatePassword(it) }

     fun validateEmail(email: String) : Error? =
         when {
             email.isEmpty() -> throw EmailError.Empty
             email.contains("@") -> null
             else -> throw EmailError.NotValid
        }
// Similarly for password …
}

然后在您的文本输入中调用viewModel.setEmailValue(value) 中的OnChangeListener,这样您每次击键都会获得更新的emailErrorpasswError

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-20
    • 1970-01-01
    • 2019-10-22
    • 2017-03-15
    相关资源
    最近更新 更多