I'm trying to implement One Tap, so I have created a function that looks like this:
override suspend fun oneTapSgnInWithGoogle() = flow {
try {
emit(Result.Loading)
val result = oneTapClient.beginSignIn(signInRequest).await()
emit(Result.Success(result))
} catch (e: Exception) {
Log.d(TAG, "oneTapSgnInWithGoogle: ${e.message}")
emit(Result.Error(e.message!!))
}
}
If I use flow
and try to emit
the result, my app crashed with the following message:
Flow exception transparency is violated: StandaloneCoroutine has completed normally; but then emission attempt of value 'Error(message=StandaloneCoroutine has completed normally)' has been detected.
However, if change the code to:
override suspend fun oneTapSgnInWithGoogle() = channelFlow {
try {
send(Result.Loading)
val result = oneTapClient.beginSignIn(signInRequest).await()
send(Result.Success(result))
} catch (e: Exception) {
Log.d(TAG, "oneTapSgnInWithGoogle: ${e.message}")
send(Result.Error(e.message!!))
}
}
And I use channelFlow
and try to send
the result, the app isn't crashing but I still get the error message saying:
StandaloneCoroutine has completed normally
How can I emit the result correctly and get rid of this error message?
P.S. In my ViewModel class I use:
fun oneTapSgnInWithGoogle() = liveData(Dispatchers.IO) {
viewModelScope.launch {
repo.oneTapSgnInWithGoogle().collect { result ->
emit(result)
}
}
}
CodePudding user response:
This is not a good practice to launch a coroutine in liveData
block. liveData
block is a suspend
lambda, you can collect values directly in it without launching a coroutine:
fun oneTapSgnInWithGoogle() = liveData(Dispatchers.IO) {
repo.oneTapSgnInWithGoogle().collect { result ->
emit(result)
}
}
In your case liveData
block has already finished execution (and corresponding coroutine, in which liveData
block is executed) when you try to emit a value to LiveData
. The solution above should solve the problem.