skip to Main Content

I’m using this code to get my user from the Firebase Realtime Database in my Android app:

    private var _user = getUser(firebaseAuth.currentUser?.uid ?: "NULL")
    .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)

The idea is that I can get flow updates about the user from the database, and when the user isn’t logged in, (firebaseAuth.currentUser == null) the database reference is NULL and so the _user would be null.

But when I’m trying to log in, for example, I’m updating firebaseAuth.currentUser but the getUser function isn’t recalled so the app still thinks _user is null.

I have 2 Questions:

  • How can update the value of _user (or recall getUser) as soon
    as I login (when firebaseAuth.currentUser changes?)?
  • And if that’s not possible, how can I manually recall getUser and set the value of _user?

Here is my getUser function (if that help):

    private fun getUser(userId: String): Flow<User?> {
    return callbackFlow {
        val userRef = databaseReference.child("Users/$userId")
        val listener = userRef.addValueEventListener(object : ValueEventListener {
            override fun onDataChange(dataSnapshot: DataSnapshot) {
                val user = dataSnapshot.getValue<User>()
                trySend(user)
            }
            override fun onCancelled(error: DatabaseError) {
                // Cancel the flow on error
                cancel()
            }
        })
        // Return the listener to be used to cancel the flow
        awaitClose {
            userRef.removeEventListener(listener)
            channel.close()
        }

    }
}

2

Answers


  1. To solve this issue you have to use a FirebaseAuth.AuthStateListener which contains a method called onAuthStateChanged(auth: FirebaseAuth) which is triggered each time the auth state changes.

    Now when it comes to Kotlin, it’s best to use a callbackFlow. In code it should look like this:

    fun getAuthState(viewModelScope: CoroutineScope) = callbackFlow {
        val authStateListener = AuthStateListener { auth ->
            trySend(auth.currentUser == null)
        }
        auth.addAuthStateListener(authStateListener)
        awaitClose {
            auth.removeAuthStateListener(authStateListener)
        }
    }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), auth.currentUser == null)
    
    Login or Signup to reply.
  2. You need to wait for user object be available upon authentication

    private val currentUser = callbackFlow {
            if (firebaseAuth.currentUser?.uid != null) {
                trySend(firebaseAuth.currentUser!!)
                awaitClose {
    
                }
                return@callbackFlow
            }
            val listener = FirebaseAuth.AuthStateListener {
                val user = it.currentUser ?: return@AuthStateListener
                if (!user.uid.isNullOrEmpty()) {
                    trySend(user)
                }
            }
            firebaseAuth.addAuthStateListener(listener)
            awaitClose {
                firebaseAuth.removeAuthStateListener(listener)
            }
        }.shareIn(
            scope = scope + "Current user",
            started = SharingStarted.Eagerly,
            replay = 1
        )
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search