我正在尝试使用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 up
或Login
。预期的设计是当用户单击按钮时,当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
加载动画,而不是预期的文本。因此,我需要找到一种方法,仅在用户单击注册或登录按钮时才开始从流中收集。
我怎样才能做到这一点?
先谢了。
1条答案
按热度按时间kwvwclae1#
我在评论中的建议很简单:
onAuthenticate(...)
的操作。viewModel.onAuthenticate(...)
。viewModelScope.launch { ... }
并调用uiState.Loading()
,然后调用authenticate(...)
,处理它,并发出uiState.Success(...)
(或错误)。有多种方法可以接近步骤4。
你可以有一系列的内部流,你最终
combine(...)
,或者只是用.map
等本地处理,甚至把大部分委托给注入的use-case
或类似类中的suspend函数:伪代码:
你可以在你的虚拟机中注入上面的代码,这样你就可以(在虚拟机中)拥有如下内容:
你的UI很开心。