https://kotlinlang.org logo
#coroutines
Title
# coroutines
k

Kulwinder Singh

10/08/2019, 11:16 AM
i'm using this
callbackFlow
to listen updates of Firestore Collection using below extension function
Copy code
@ExperimentalCoroutinesApi
fun Query.getQuerySnapshotFlow(): Flow<QuerySnapshot?> = callbackFlow {
    val listenerRegistration = addSnapshotListener { querySnapshot, e ->
        if (e != null) {
            cancel(message = "", cause = e)
            return@addSnapshotListener
        }
        offer(querySnapshot)
    }
    awaitClose {
        listenerRegistration.remove()
    }
}

@ExperimentalCoroutinesApi
fun <T> Query.getDataFlow(mapper: (QuerySnapshot?) -> T): Flow<T> {
    return getQuerySnapshotFlow().map { mapper(it) }
}
and i'm using above extension functions like below inside my ViewModel, but how can i cancel previous
Flow
, which is started in
else
case below, because when
switchMap
is called again then it will keep listening old Collection and will start new one. how can i fix this?
Copy code
val myAppointments = _appointmentDate.switchMap { date ->
	//HERE I WANT TO CANCEL PREVIOUS FLOW STARTED IN ELSE CASE BELOW
	liveData {
		if (date == null)
			emit(AppointmentState.NoAppointment)
		else {
			myCollection.whereEqualTo(Appointment.DATE, date)
					.getDataFlow { it!!.toObjects<List<Appointment>>() }
					.collect { emit(AppointmentState.Loaded(it)) }
		}
	}
}
m

Manuel Vivo

10/08/2019, 11:21 AM
Easiest way I can think of is by passing a
Job
to the
liveData
builder and cancel it when needed
k

Kulwinder Singh

10/08/2019, 11:35 AM
@Manuel Vivo so something like this would be ok ?
Copy code
val appointmentJob = Job()
val myAppointments = _appointmentDate.switchMap { 
    appointmentJob.complete()
    liveData(appointmentJob) { /.../ }
}
or do i have to add
+ <http://Dispatcher.IO|Dispatcher.IO>
or other with
Job
?
m

Manuel Vivo

10/08/2019, 12:04 PM
liveData
uses
Dispatchers.Main
Copy code
var appointmentJob: Job?
val myAppointments = _appointmentDate.switchMap { date ->
    appointmentJob.cancelIfActive()
    appointmentJob = Job()
    liveData(appointmentJob) { /.../ }
    ...
}

fun Job?.cancelIfActive() {
    if (this?.isActive == true) {
        cancel()
    }
}
if you cancel a Job, you cannot use it anymore. That's why you need a fresh instance before calling
liveData
k

Kulwinder Singh

10/09/2019, 5:35 AM
thanks @Manuel Vivo it worked 👍
m

Manuel Vivo

10/09/2019, 7:52 AM
Great! My pleasure
53 Views