as invers to the question asked here How to convert Flow<List<Object>>
to Flow<Object>
I want to convert my Flow<Object>
to Flow<List<Object>>
.
At least I think I want that, so I try to explain what I want to achieve and give some background. I am working on an Android application that uses bluetooth to scan and connect to BLE devices. I'm fairly new to the Android platform and kotlin so I haven't quite grasped all the details despite all the many things I've already learnt.
My repository has a method which returns a Flow of ScanResults from the bluetooth adapter:
fun bluetoothScan(): Flow<ScanResult> {
return bluetoothStack.bluetoothScan()
}
My ViewModel consumes that function, maps the data to my BleScanResult and returns it as LiveData.
val scanResults: LiveData<BleScanResult> =
scanEnabled.flatMapLatest { doScan ->
if (doScan) {
repository.bluetoothScan().map { BleScanResult(it.device.name, it.device.address) }
} else {
emptyFlow()
}
}.asLiveData()
In my activity I want to observer on that data and display it in a RecyclerView:
val adapter = ScanResultListAdapter()
binding.rcBleScanResults.adapter = adapter
viewModel.scanResults.observe(this) { result ->
//result.let { adapter.submitList(it) }
}
The problem is that scanResults
is from type Flow<BleScanResult>
and not Flow<List<BleScanResult>>
, so the call to adapter.submitList(it)
throws an error as it
is expected to be a list.
So, how do I convert Flow
to Flow<List>
(with additional filtering of duplicates)? Or is there something I miss about the conception of Flow/LiveData?
CodePudding user response:
You can try to use a MutableList
and fill it with the data you get form a Flow
, something like the following:
val results: MutableList<BleScanResult> = mutableListOf()
val scanResults: LiveData<List<BleScanResult>> =
scanEnabled.flatMapLatest { doScan ->
if (doScan) {
repository.bluetoothScan().map {
results.apply {
add(BleScanResult(it.device.name, it.device.address))
}
}
} else {
emptyFlow()
}
}.asLiveData()
You can also use a MutableSet
instead of MutableList
if you want to have a unique list of items (assuming BleScanResult
is a data
class).
CodePudding user response:
You could use the liveData
builder to collect the Flow's values into a MutableList.
Here I copy the MutableList using toList()
before emitting it since RecyclerView Adapters don't play well with mutable data sources.
val scanResults: LiveData<List<BleScanResult>> = liveData {
val list = mutableListOf<BleScanResult>()
scanEnabled.flatMapLatest { doScan ->
if (doScan) {
repository.bluetoothScan().map { BleScanResult(it.device.name, it.device.address) }
} else {
emptyFlow()
}
}.collect {
list = it
emit(list.toList())
}
}