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 PMlouiscad
03/27/2019, 6:38 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 PMLilly
04/04/2019, 12:20 AMstartScan 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 AMlouiscad
04/04/2019, 11:28 AMLilly
04/04/2019, 11:43 AMLilly
04/04/2019, 11:48 AMlouiscad
04/04/2019, 12:13 PMLilly
04/04/2019, 12:16 PMlouiscad
04/04/2019, 12:52 PM