reactormonk
08/16/2023, 7:22 PMsuspend fun searchForCard(cardType: Byte) {
Log.d(TAG, "Search for a card once.")
writeCharacteristic(readerGatt, comByteManager.AActivityComByte(cardType), WRITE_TYPE_NO_RESPONSE).suspend()
singleSweepCardJob.cancel()
singleSweepCardJob = Job()
val scope = CoroutineScope(singleSweepCardJob)
scope.launch {
delay(1000)
Log.i(TAG, "Repeating searchForCard")
searchForCard(cardType)
}
}
private var singleSweepCardJob = Job()
Because sometimes, the bluetooth device doesn't answer properly, I'm repeating the request. I'm invoking singleSweepCardJob.cancel()
as soon as I get a response to the command. Will this blow up in my face somehow? (Code not tested yet, device is a bit further away)Casey Brooks
08/16/2023, 7:41 PMflow.mapLatest
operator is implemented, so in general it’s not necessarily a “bad” pattern. Although in this case, it looks like the launched coroutine has side-effects (searchForCard doesn’t return anything, so it presumably updates a state value internally) which does have the possibility of race conditions if the first scope is cancelled but the coroutine is not fully completed by the time you launch the second one.
That said, I saw an elegant solution for “restartable coroutines” recently, that might make it look a bit cleaner and easier to understand the logic, as well as being safe against such side-effects https://kotlinlang.slack.com/archives/C1CFAFJSK/p1690215505119029?thread_ts=1690214570.291329&cid=C1CFAFJSKreactormonk
08/17/2023, 8:46 AM