Android:按下按钮时开始从Flow收集?

pkln4tw6  于 2023-03-27  发布在  Android
关注(0)|答案(1)|浏览(143)

我正在尝试使用Firebase身份验证构建注册和登录屏幕。
当用户输入电子邮件和密码时,他们可以单击注册或登录按钮,随后向Firebase发出网络请求以执行相应的操作。
现在,网络请求返回一个Flow,对于登录操作和注册操作类似:

fun authenticate(email: String, password: String): Flow<NetworkResponse<Boolean>> = flow {
    emit(NetworkResponse.Loading)
    try {
        auth.signInWithEmailAndPassword(email, password).await()
        emit(NetworkResponse.Success(true))
    } catch (e: Exception) {
        emit(NetworkResponse.Error(e))
    }
}

UI中的按钮显示一些文本,如Sign upLogin。预期的设计是当用户单击按钮时,当Flow发出NetworkResponse.Loading时,将显示加载动画,然后对NetworkResponse.Success执行某些操作或在NetworkResponse.Error上显示错误消息。
通常,我会从ViewModel收集UI状态,如下所示:

@Composable
LoginScreen(
    modifier: Modifier = Modifier,
    viewModel: LoginViewModel = hiltViewModel()
) {

    val uiState by viewModel.uiState.collectAsState()

    // ...
}

如果我对authenticate流执行此操作,则屏幕将显示NetworkResponse.Loading加载动画,而不是预期的文本。因此,我需要找到一种方法,仅在用户单击注册或登录按钮时才开始从流中收集。
我怎样才能做到这一点?
先谢了。

kwvwclae

kwvwclae1#

我在评论中的建议很简单:

  1. UI -〉Observes ViewModel.uiState(Sealed class Success/Loading/ETC.)
  2. ViewModel公开了一个类似onAuthenticate(...)的操作。
  3. UI被“tapped”,您调用viewModel.onAuthenticate(...)
  4. View Model执行viewModelScope.launch { ... }并调用uiState.Loading(),然后调用authenticate(...),处理它,并发出uiState.Success(...)(或错误)。
  5. UI观察到这一点,因此将做出相应React。
    有多种方法可以接近步骤4。
    你可以有一系列的内部流,你最终combine(...),或者只是用.map等本地处理,甚至把大部分委托给注入的use-case或类似类中的suspend函数:
    伪代码:
class AuthenticateUseCase(yourAuthRepo: AuthRepo) {
   suspend operator fun invoke((user, pass) : YourResponse {
       return yourAuthRepo.authenticate(user, pass) // or even handle errors with a `when` or similar case to decide what YourResponse means. It's usually some form of `Responses<T>` that you create.
        // this "empty" passing-hands-proxy use-case doesn't really do anything here, but it's the starting point to abstract the operation.
   }
}

你可以在你的虚拟机中注入上面的代码,这样你就可以(在虚拟机中)拥有如下内容:

fun onAuthenticate(user, pass) {
   viewModelScope.launch {
       uistate.emit(loading)
       val result = authUseCase(user, pass)
       uistate.emit(Success(result)) // obviously deal with errors, this is pseudo-code.
   }
}

你的UI很开心。

相关问题