androidkotlinkotlin-coroutineskotlin-flowgoogle-one-tap

Cannot emit data using flow or channelFlow on Android


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)
        }
    }
}

Solution

  • 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.