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.