NSDManager and co-routine
from the CommonsWare Community archivesAt April 28, 2021, 12:06pm, Jan asked:
NetworkServiceManager (NSDManager) was only working about 10% of the time until I discovered
that it works if called from a coroutine.
So I have this code:
fun startDiscovery(uuid:String) {
val scope = CoroutineScope(Job() + Dispatchers.Default)
val job = scope.launch {
val discoveryJob = async { findDevice(uuid) }
val result = discoveryJob.await()
// immediate return
delay(2000)
// after the delay, I have url to device IF it was found in discovery
--->>>> should I put the delay in another job and cancel that job in an observable???
}
fun findDevice(uuid:String) {
// NsdHelper is the usual NSD Manager helper class that has the callbacks such as onServiceResolved
val nsdHelper = NsdHelper()
// pass a lambda to be called from onServiceResolved
nsdHelper.findThisDevice(uuid,onFindDevice = { device ->
urlFullAddress = device.urlFullAddress
// urlFullAddress is what the caller needs but if device isn't found
// then it's never set so discovery service needs to be stopped at some point (probably after the time delay??)
})
}
In your co-routines book, you say:
“Conversely, the only reason to use async() over launch() is to hold onto the
Deferred that async() returns, so you can get the result of the coroutine — we will
explore this more in the next chapter.”
But the next chapter hasn’t been written yet.
I don’t know if that would help because my callback is being called from a callback
so how would I return that in lambda??? – (result = discoveryJob.await())
First problem: how to immediately know if I get a result - without waiting the full delay(2000).
Should I use an observable that then would cancel the delay (if put in a job that could be cancelled)?
Keep in mind, I may not get any result (no device on network). (I need to add call to stopDiscovery after the delay(2000) line).
The above code is not in a ViewModel but I have similar code that is in a ViewModel (in case it matters).
Is there a better way to my approach? I’m just excited I can finally get NSD to consistently discover! It used to never give me the onServiceFound callback.
At April 28, 2021, 4:29pm, Jan replied:
Darn! It is not fixed. I had bluetooth turned off. As soon as I turned bluetooth on and started its discovery process, NSDManager broke again. So now I’m NOT getting any services found.
Mark, have you run into a conflict between bluetooth discovery and NSD discovery services?
At April 28, 2021, 11:32pm, mmurphy replied:
No, but I have never tried it, either.
At April 29, 2021, 12:17pm, Jan replied:
Okay. Is there a way to return a value from the findDevice once its lambda has the device’s urlFullAddress ?
At April 29, 2021, 12:32pm, mmurphy replied:
If I understand your question, then, as with another post I made here today, you could look into using suspendCancellableCoroutine()
, to make findDevice()
be a suspend
function that adapts the callback-based NsdManager
API. See https://wares.commonsware.com/app/internal/book/Coroutines/page/chap-bridge-001.html in Elements of Kotlin Coroutines for an example.