Вернуть результат из корутины

Столкнулся с задачей и не могу ее решить. В общем я написал класс Scanner, который сканирует Bluetooth устройства. У него есть всего три метода:

  • startScan() -> Unit
  • stopScan() -> Unit
  • scanState() -> StateFlow

Метод scanState() возвращает поток c типом ScannerState. Класс ScannerState по сути является sealed классом, у которого есть два внутренних класса:

  • Found(val devices: List) - для списка найденных устройств
  • Error(val errorCode: Int) - для ошибок при сканировании

Метод scanState() не может ничего излучать сам по себе до тех пор, пока не будет вызван startScan(). В общем моя задача сделать так чтобы в репозитории был один метод fetchDevices(), который бы возвращал найденные устройства. Но я хочу сделать так, что при обращении к этому методу он так же дергал метод сканнера startScan() и заодно подписывался на метод scanState() и полученные от него результаты смаппить к классу data слоя (пусть он у меня например будет называться DevicesData). В дальнейшем что бы я его смог потом смапить к Domain и Presentation слоям.

Ну и типа репозиторий:

interface DevicesRepository {

    suspend fun fetchDevices(): Flow<DevicesData>

    class Base(): DevicesRepository {
        override suspend fun fetchDevices(): Flow<DevicesData> {
            // .. тут реализация
        }
    } 
}

Интерфейс и реализация DevicesScannerDataSource.kt

interface DevicesScannerDataSource {

    fun startScan()
    fun stopScan()

    fun scanState(): StateFlow<DevicesScannerState>

    class Base : DevicesScannerDataSource {

        private val adapter: BluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
        private val scanResults: MutableMap<String, BluetoothDevice> = mutableMapOf()
        private var scanCallback: ScanCallback? = null
        private var scanner: BluetoothLeScanner? = null

        private val scannerState = MutableStateFlow<DevicesScannerState>(DevicesScannerState.Found(emptyList()))

        private val filters: List<ScanFilter>
        private val settings: ScanSettings

        init {
            settings = buildSettings()
            filters = buildFilters()
        }

        override fun startScan() {
            if (scanCallback == null) {
                scanner = adapter.bluetoothLeScanner
                scanCallback = ScanResultsCallback()
                scanner?.startScan(filters, settings, scanCallback)
            } else {
                Log.e("Scan", "Already scan")
            }
        }

        override fun stopScan() {
            if (scanCallback != null) {
                scanner?.stopScan(scanCallback)
                scanCallback = null
                scanner = null
            }
        }

        override fun scanState(): StateFlow<DevicesScannerState> = scannerState

        private fun buildSettings() = ScanSettings.Builder()
            .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
            .build()

        private fun buildFilters(): List<ScanFilter> {
            return listOf<ScanFilter>(ScanFilter.Builder().build())
        }

        private fun emitDevices(scanResults: MutableMap<String, BluetoothDevice>) {
            scannerState.tryEmit(DevicesScannerState.Found(scanResults.values.toList()))
        }

        private fun emitError(code: Int) {
            scannerState.tryEmit(DevicesScannerState.Error(code))
        }

        private inner class ScanResultsCallback : ScanCallback() {
            override fun onScanResult(callbackType: Int, result: ScanResult) {
                scanResults[result.device.address] = result.device
                emitDevices(scanResults)
            }

            override fun onBatchScanResults(results: MutableList<ScanResult>) {
                results.forEach { result ->
                    scanResults[result.device.address] = result.device
                }
                emitDevices(scanResults)
            }

            override fun onScanFailed(errorCode: Int) {
                emitError(errorCode)
            }
        }
    }
}

Класс DevicesScannerState

sealed class DevicesScannerState {
    data class Found(val devices: List<BluetoothDevice>): DevicesScannerState()
    data class Error(val errorCode: Int): DevicesScannerState()
}

Ответы (0 шт):