Colton Idle
11/19/2021, 8:00 AMsuspend fun getThingFlow(myId: String): Flow<Thing?> {
val thingFlow = MutableStateFlow<Thing?>(null)
FirebaseFirestore.getInstance()
.document("things/$myId")
.addSnapshotListener { value, error ->
thingFlow.emit(value!!.toObject<Thing>())
}
return thingFlow
}
Colton Idle
11/19/2021, 8:06 AMsuspendCoroutine {
and
callbackFlow
are popular. Just overall confused on which would be the best approach here.KamilH
11/19/2021, 8:07 AMsuspend fun getThingFlow(myId: String): Flow<Thing?> =
suspendCancellableCoroutine<Thing> { continuation ->
FirebaseFirestore.getInstance()
.document("things/$myId")
.addSnapshotListener { value, error ->
continuation.resume(value!!.toObject<Thing>()) // note that this `resume` method is extension function one, so you need to import it
}
it.invokeOnCancellation {
// do the cleanup here
}
}
KamilH
11/19/2021, 8:08 AMFirebaseFirestore
API, so be careful copy-pasting it, but generally it should be something like aboveColton Idle
11/19/2021, 8:12 AMColton Idle
11/19/2021, 8:15 AMKamilH
11/19/2021, 8:15 AMsuspend fun getThingFlow(myId: String): Flow<Thing?> =
callbackFlow<Thing?> {
FirebaseFirestore.getInstance()
.document("things/$myId")
.addSnapshotListener { value, error ->
trySend(value!!.toObject<Thing>())
}
invokeOnClose {
// do the cleanup here
}
}
KamilH
11/19/2021, 8:17 AMFirebaseFirestore
API, so if there is any indication that this stream is finished (closed) you can use close()
function to close this flow
Colton Idle
11/19/2021, 8:18 AMColton Idle
11/19/2021, 8:21 AMTgo1014
11/19/2021, 8:59 AMcallbackFlow
is the way to go, but honestly I’m impressed there’s no flow api for Firebase SDK yethfhbd
11/19/2021, 10:49 AMJoffrey
11/19/2021, 10:56 AMcallbackFlow
approach, the function shouldn't be suspending. Also, the listener should be assigned to a variable so it can be unregistered in awaitClose
. (see the docs for callbackFlow, they are pretty helpful)Colton Idle
11/19/2021, 7:21 PMfun getThingFlow(myId: String): Flow<Thing?> =
callbackFlow<Thing?> {
val listener = FirebaseFirestore.getInstance()
.document("things/$myId")
.addSnapshotListener { value, error ->
trySend(value!!.toObject<Thing>())
}
invokeOnClose {
listener.close()
}
}
Thanks everyone!hfhbd
11/20/2021, 12:27 AMfun getThingFlow(myId: String): Flow<Thing?> =
callbackFlow<Thing?> {
val listener = FirebaseFirestore.getInstance()
.document("things/$myId")
.addSnapshotListener { value, error ->
trySend(value!!.toObject<Thing>())
}
invokeOnClose {
close()
}
awaitClose {
listener.close()
}
Colton Idle
11/21/2021, 3:52 AMJoffrey
11/21/2021, 11:02 AMinvokeOnClose
should be called at all here. Only awaitClose
hfhbd
11/21/2021, 11:13 AMinvokeOnClose
function should be part of listener
to finish/close the flow when all items are emitted. Otherwise, this flow will never finish by itself.Joffrey
11/21/2021, 11:14 AMinvokeOnClose
shouldn't be called in the listener either, only close()
should (when you want to close the channel of the flow). invokeOnClose
is a callback on the SendChannel
itself, why doesn't really have its place in a callbackFlow
setup AFAIUhfhbd
11/21/2021, 11:16 AMfun getThingFlow(myId: String): Flow<Thing?> =
callbackFlow<Thing?> {
val listener = FirebaseFirestore.getInstance()
.document("things/$myId")
.addSnapshotListener { value, error ->
trySend(value!!.toObject<Thing>())
}
listener.onError { // I dont know the FireStore API
close(it)
}
listener.invokeOnClose { // or onFinished. I dont know the FireStore API...
close()
}
awaitClose {
listener.close()
}
Joffrey
11/21/2021, 11:26 AMinvokeOnClose
was that of the SendChannel
, and is an existing function. I didn't get that you were talking about a hypothetical closing callback of the listener. There is no such thing AFAIK in this case, it's just a subscription to receive updates. It has no end in itself, so the only way to end the flow is by cancelling it from the collector side, which awaitClose
is meant to handle:
fun getThingFlow(myId: String): Flow<Thing?> =
callbackFlow<Thing?> {
val listener = FirebaseFirestore.getInstance()
.document("things/$myId")
.addSnapshotListener { value, error ->
trySend(value!!.toObject<Thing>())
}
awaitClose {
listener.close()
}
}
hfhbd
11/21/2021, 11:31 AMColton Idle
11/22/2021, 6:33 PMJoffrey
11/22/2021, 6:33 PMColton Idle
11/22/2021, 6:34 PMJoffrey
11/22/2021, 6:35 PMawaitClose
anywhere, your flow will terminate immediately. invokeOnClose
just registers a handler but doesn't waitJoffrey
11/22/2021, 6:35 PMColton Idle
11/22/2021, 6:36 PMJoffrey
11/22/2021, 8:21 PMColton Idle
11/22/2021, 9:28 PMfun getThingFlow(myId: String): Flow<Thing?> =
callbackFlow<Thing?> {
val listener = FirebaseFirestore.getInstance()
.document("things/$myId")
.addSnapshotListener { value, error ->
trySend(value!!.toObject<Thing>())
}
awaitClose {
listener.remove()
}
}
The only real change I made was listener.remove() since there is no close() api (i dont know where I got that from)Colton Idle
08/13/2022, 1:36 PM