Kotlin Flow问题:ViewModel中collect代码块未执行
ViewModel中Flow的collect代码块未执行问题排查
我无法理解为何ViewModel中的collect代码块未执行,此前项目中从未出现该问题。函数本身运行正常,但无法收集返回结果。尝试使用onEach+launchIn的方式收集Flow,结果依旧无效,日志仅输出collect外部的内容。
相关代码
ViewModel代码
fun sendOtp(activity: Activity) { viewModelScope.launch { Timber.tag("View Model - Outside Collect").i("Outside Collect") authUseCase.sendOtp(activity, _authState.value.phoneNumber).collect { result -> Timber.tag("View Model - Inside Collect").i("$result") when (result) { is Resource.Success -> Timber.tag("VIEW MODEL - SUCCESS").i("${result.message} | ${result.data}") is Resource.Error -> Timber.tag("VIEW MODEL - ERROR").e("${result.message} | ${result.data}") is Resource.Loading -> Timber.tag("VIEW MODEL - LOADING").d("${result.message} | ${result.data}") } } } }
UseCase代码
class SendOtpImpl @Inject constructor( private val authRepository: AuthRepository ): SendOtp { override operator fun invoke(activity: Activity, phoneNumber: String): Flow<Resource<String>> = flow { authRepository.sendOtp(activity, phoneNumber).onStart { emit(Resource.Loading("OTP Code will be sent to +$phoneNumber")) }.collect() } }
Repository代码
override fun sendOtp(activity: Activity, phoneNumber: String): Flow<Resource<String>> = flow { val options = _authBuilder .setActivity(activity) .setPhoneNumber("$phoneNumber") .build() PhoneAuthProvider.verifyPhoneNumber(options) emit(_callbacksState.value) Timber.tag("Repository").d("${_callbacksState.value.data}") }
尝试的另一种收集方式
authUseCase.sendOtp(activity, _authState.value.phoneNumber).onEach { result -> when (result) { is Resource.Success -> Timber.tag("VIEW MODEL VERIFY - SUCCESS").i("${result.message} | ${result.data}") is Resource.Error -> Timber.tag("VIEW MODEL VERIFY - ERROR").e("${result.message} | ${result.data}") is Resource.Loading -> Timber.tag("VIEW MODEL VERIFY - LOADING").d("${result.message} | ${result.data}") } }.launchIn(viewModelScope)
问题根源
1. UseCase的Flow未传递数据
SendOtpImpl中创建的Flow仅内部收集了Repository的Flow,但未将收集到的结果发射到外层Flow。这导致UseCase返回的Flow全程没有输出任何数据,ViewModel的collect代码块自然不会触发。
2. Repository的异步逻辑处理错误
PhoneAuthProvider.verifyPhoneNumber是异步操作,调用后立刻emit(_callbacksState.value)时,回调尚未执行,此时_callbacksState大概率是初始状态。且如果_callbacksState不是可观察的Flow(如StateFlow),后续回调更新的值也无法被上层感知。
修复方案
修复UseCase
使用emitAll替代内部collect,将Repository Flow的所有发射值传递到外层:
class SendOtpImpl @Inject constructor( private val authRepository: AuthRepository ): SendOtp { override operator fun invoke(activity: Activity, phoneNumber: String): Flow<Resource<String>> = authRepository.sendOtp(activity, phoneNumber) .onStart { emit(Resource.Loading("OTP Code will be sent to +$phoneNumber")) } }
修复Repository
将_callbacksState改为MutableStateFlow,在PhoneAuth回调中更新它,并通过emitAll暴露状态变化:
private val _callbacksState = MutableStateFlow<Resource<String>>(Resource.Idle) val callbacksState: StateFlow<Resource<String>> = _callbacksState override fun sendOtp(activity: Activity, phoneNumber: String): Flow<Resource<String>> = flow { val options = _authBuilder .setActivity(activity) .setPhoneNumber("$phoneNumber") .setCallbacks(object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() { override fun onVerificationCompleted(credential: PhoneAuthCredential) { _callbacksState.value = Resource.Success("Verification completed", credential.smsCode) } override fun onVerificationFailed(e: FirebaseException) { _callbacksState.value = Resource.Error(e.message ?: "Verification failed", null) } override fun onCodeSent(verificationId: String, token: PhoneAuthProvider.ForceResendingToken) { _callbacksState.value = Resource.Success("Code sent", verificationId) } }) .build() PhoneAuthProvider.verifyPhoneNumber(options) emitAll(callbacksState) }
验证ViewModel逻辑
修复上述问题后,ViewModel的两种收集方式均可正常触发,无需额外修改。
内容的提问来源于stack exchange,提问作者Raffly
相关产品推荐
相关产品推荐

