Home > Mobile >  How to remove the listener when using StateFlow<Boolean>?
How to remove the listener when using StateFlow<Boolean>?

Time:12-08

Earlier, I have used this function:

override fun getAuthResponse() = callbackFlow  {
    val listener = AuthStateListener {
        trySend(it.currentUser == null)
    }
    auth.addAuthStateListener(listener)
    awaitClose {
        auth.removeAuthStateListener(listener)
    }
}

But due to some constraints that are explained here I had to use:

override fun getAuthResponse(): StateFlow<Boolean> {
    val flow = MutableStateFlow(auth.currentUser == null)
    val listener = AuthStateListener {
        flow.value = it.currentUser == null
    }
    auth.addAuthStateListener(listener)
    return flow
}

Which is what I need, but I cannot find awaitClose {...}, so I can remove the listener. How to remove the listener when using StateFlow?

CodePudding user response:

You can use your callback flow with stateIn to turn it into a StateFlow that only uses a listener when it has collector(s). When it loses all collectors, WhileSubscribed causes the upstream callback flow to terminate, so it will remove the listener. When it gets a new first collector, it restarts the upstream flow from scratch.

To use stateIn, you must have a coroutine scope available to run the state flow conversion in. I'm just using GlobalScope for this example. If this is in a ViewModel you might want to use viewModelScope instead. Or you could make the coroutine scope an input parameter of the function. I think GlobalScope is probably OK due to the use of WhileSubscribed().

override fun getAuthResponse(): StateFlow<Boolean> = callbackFlow  {
    send(it.currentUser == null)
    val listener = AuthStateListener {
        trySend(it.currentUser == null)
    }
    auth.addAuthStateListener(listener)
    awaitClose {
        auth.removeAuthStateListener(listener)
    }
}.stateIn(GlobalScope, SharingStarted.WhileSubscribed(), auth.currentUser == null)
  • Related