gpt4 book ai didi

android - ui中再次收集StateFlow最后一个值

转载 作者:行者123 更新时间:2023-12-04 23:44:19 28 4
gpt4 key购买 nike

所以最近我一直在使用 StateFlow、SharedFlow 和 Channels API,但我在尝试将我的代码从 LiveData 迁移到表示层中的 StateFlow 时遇到了一个常见的用例。
我面临的问题是,当我发出数据并在 viewModel 中收集它时,我可以将值设置为 mutableStateFlow,当它最终到达 fragment 时,它使用 Toast 显示一些信息性消息,让用户知道是否有错误发生或一切顺利。接下来,有一个按钮可以导航到另一个 fragment ,但是如果我返回到已经有失败 Intent 的结果的上一个屏幕,它会再次显示 Toast。这正是我想要弄清楚的。如果我已经收集了结果并将消息显示给用户,我不想继续这样做。如果我导航到另一个屏幕并返回(当应用程序从后台返回时也会发生这种情况,它会再次收集最后一个值)。 LiveData 并没有发生这个问题,我只是做了完全相同的事情,从存储库公开流并通过 ViewModel 中的 LiveData 收集。
代码:

class SignInViewModel @Inject constructor(
private val doSignIn: SigninUseCase
) : ViewModel(){

private val _userResult = MutableStateFlow<Result<String>?>(null)
val userResult: StateFlow<Result<String>?> = _userResult.stateIn(viewModelScope, SharingStarted.Lazily, null) //Lazily since it's just one shot operation

fun authenticate(email: String, password: String) {
viewModelScope.launch {
doSignIn(LoginParams(email, password)).collect { result ->
Timber.e("I just received this $result in viewmodel")
_userResult.value = result
}
}
}

}
然后在我的 fragment 中:
override fun onViewCreated(...){
super.onViewCreated(...)

launchAndRepeatWithViewLifecycle {
viewModel.userResult.collect { result ->
when(result) {
is Result.Success -> {
Timber.e("user with code:${result.data} logged in")
shouldShowLoading(false)
findNavController().navigate(SignInFragmentDirections.toHome())
}
is Result.Loading -> {
shouldShowLoading(true)
}
is Result.Error -> {
Timber.e("error: ${result.exception}")
if(result.exception is Failure.ApiFailure.BadRequestError){
Timber.e(result.exception.message)
shortToast("credentials don't match")
} else {
shortToast(result.exception.toString())
}

shouldShowLoading(false)
}
}
}
}
launchAndRepeatWithViewLifecycle 扩展功能:
inline fun Fragment.launchAndRepeatWithViewLifecycle(
minActiveState: Lifecycle.State = Lifecycle.State.STARTED,
crossinline block: suspend CoroutineScope.() -> Unit
) {
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.lifecycle.repeatOnLifecycle(minActiveState) {
block()
}
}
}
关于为什么会发生这种情况以及如何使用 StateFlow 解决它的任何想法?我也尝试使用带有 replay = 0 的 SharedFlow 和带有 receiveAsFlow() 的 Channels,但随后出现了其他问题。

最佳答案

您可以像这样创建扩展函数:

fun <T> MutableStateFlow<T?>.set(value: T, default: T? = null) {
this.value = value
this.value = default
}
它在发出新值后设置所需的默认值。就我而言,我使用 null 作为所需的值。
在 ViewModel 内部,您可以使用 set() 而不是直接设置值扩展功能。
fun signIn() = authRepository.signIn(phoneNumber.value).onEach {
_signInState.set(it)
}.launchIn(viewModelScope)

关于android - ui中再次收集StateFlow最后一个值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68274359/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com