Lilly
03/27/2019, 5:53 PMproduce
method is available within `scan`:
@ObsoleteCoroutinesApi
@ExperimentalCoroutinesApi
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
fun scan(filters: List<ScanFilter>?, settings: ScanSettings): ReceiveChannel<ScanResult> {
requireSafeSettings(settings)
return produce(context) { // unresolvable reference
val scanResultsChannel = Channel<ScanResult>(capacity = UNLIMITED)
val scanCallback = ScanCallback(scanResultsChannel)
scanner.startScan(filters, settings, scanCallback)
scanResultsChannel.consumeEach { send(it) }
scanResultsChannel.invokeOnClose { scanner.stopScan(scanCallback) }
if (SDK_INT >= O_MR1 && scanCallback.isScanningTooFrequently()) {
scanResultsChannel.close(ScanFailedException(SCAN_FAILED_SCANNING_TOO_FREQUENTLY))
}
}
}
I call this method within ScannerLiveData
class that extends from LiveData:
fun startScan() {
if (isScanning) {
return
}
scanChannel = scanner.scan(null, settings)
scanChannel.consumeEach { // unresolvable reference
// Todo
}
isScanning = true
}
My ScannerLiveData
object gets injected in my ScannerViewModel
where I simply call startScan()
. I don't know how to provide a scope to use the scan
method. I know there is a predefined viewModelScope
...The only idea I have is to pass this scope down to scan
method. Can someone help?tseisel
03/27/2019, 6:06 PMScannerLiveData
instances live longer that its ViewModel
?
If no, create instances of ScannerLiveData
by passing the scope of the viewmodel. Otherwise, you have to define your own scope for your LiveData and cancel it when it is not longer required.Lilly
03/27/2019, 6:26 PMScannerLiveData
doesn't live longer so I would pass the viewmodel scope to ScannerLiveData
via constructor but will I have to pass the scope to scan
method too?louiscad
03/27/2019, 6:31 PMLilly
03/27/2019, 6:33 PMlouiscad
03/27/2019, 6:36 PMtseisel
03/27/2019, 6:44 PMreturn scope.produce { ... }
Note that you need to pass a parameter to produce
only if you want the producer coroutine to have some context (for example, move away from the main thread by passing <http://Dispatchers.IO|Dispatchers.IO>
)Lilly
03/27/2019, 7:19 PMscanResultsChannel
. Isn't there a possibility to just have one channel, i.e. create a channel outside of your library and pass it to scan
and then to ScanCallback
?
@tseisel Thanks Sir and ty for the interesting bonus information 🙂louiscad
03/27/2019, 11:33 PMLilly
03/27/2019, 11:50 PMstartScan
method of my ScannerLiveData
object which looks like:
@ExperimentalCoroutinesApi
@ObsoleteCoroutinesApi
fun startScan(viewModelScope: CoroutineScope) {
if (isScanning) {
return
}
scanChannel = scanner.scanChannel(null, settings).apply {
viewModelScope.launch { consumeEach { deviceDiscovered(it) } }
}
isScanning = true
}
As you can see I pass the viewModelScope
--> should I call cancel
for this scope in onCleared
method of viewModel or in stopScan
method in viewModel? Thanks in advance!louiscad
04/04/2019, 10:17 AMcoroutineScope { … }
, or a coroutine builder.
Note that Flow
(aka. cold streams from kotlinx.coroutines) is coming and should be a better fit for that API, and when the API is stable enough, I'll likely update BleScanCoroutines for it.Lilly
04/04/2019, 11:18 AMscanChannel = scanner.scanChannel(null, settings)
for (result in scanChannel) deviceDiscovered(result)
Btw I'm using the viewModelScope
provided by viewmodel-ktx
, just wasn't sure if it gets canceled automatically, but you're right.louiscad
04/04/2019, 11:27 AMLilly
04/04/2019, 11:43 AMlouiscad
04/04/2019, 12:13 PMLilly
04/04/2019, 12:16 PMlouiscad
04/04/2019, 12:52 PM