Ryan Smith
11/03/2022, 12:08 AMOutlinedTextField
and a DropdownMenu
. Here is the definition for it:
fun <T : Any> Spinner(viewModel: SpinnerViewModel<T>, modifier: Modifier = Modifier)
And here is the SpinnerViewModel
interface:
interface SpinnerViewModel<T : Any> {
val items: Flow<List<T>>
var selectedItem: T?
}
The Composable is stateful and does the following:
val items = viewModel.items.collectAsState(emptyList())
val windowValue = derivedStateOf { viewModel.selectedItem?.toString() ?: "Select" }
val expanded = remember { mutableStateOf(false) }
and then uses items
and expanded
as state for the DropdownMenu
and windowValue
for the OutlinedTextField
.
The items themselves are produced by a periodic job upstream that runs adb devices
every second, maps the output to a collection of models, and then emits that collection downstream:
private val timer = flow {
println("Timer flow starting")
while (currentCoroutineContext().isActive) {
emit(Unit)
delay(1000L)
}
}
private val adbWatcherContext = newSingleThreadContext("adb-devices-watcher")
val devices: Flow<Set<Device>> = timer.mapNotNull { refreshDevices() }.flowOn(adbWatcherContext)
The weird thing is that every time I click the "Spinner" to expand it the whole Flow seems to be restarted since I see the "Timer flow starting" console message showing up with every click. Presumably I'm just piling new Jobs on to my coroutine context without canceling previous ones (or something even worse).
I appreciate any insight you can offer as to what I'm doing wrong here or what a better approach might be! And sorry for what I'm certain is an extra amount of dumb sprinkled in to my code snippets while I'm still figuring things out.