Wie rufe ich Kotlin-Coroutine in zusammensetzbaren Funktionsrückrufen auf?
Lesezeit: 3 Minuten
Nycta
Ich möchte eine Suspend-Funktion innerhalb eines Callbacks einer Composable-Funktion aufrufen.
suspend fun getLocation(): Location? { /* ... */ }
@Composable
fun F() {
val (location, setLocation) = remember { mutableStateOf<Location?>(null) }
val getLocationOnClick: () -> Unit = {
/* setLocation __MAGIC__ getLocation */
}
Button(onClick = getLocationOnClick) {
Text("detectLocation")
}
}
Wenn ich Rx verwendet hätte, dann könnte ich es einfach tun subscribe.
ich könnte invokeOnCompletion und dann getCompletedaber diese API ist experimentell.
Ich kann es nicht verwenden launchInComposition In getLocationOnClick Weil launchInComposition Ist @Composable Und getLocationOnClick kann nicht sein @Composable.
Was wäre der beste Weg, um das Ergebnis einer Suspendierungsfunktion innerhalb einer regulären Funktion innerhalb zu erhalten? @Composable Funktion?
Sie können eine Funktion eines ViewModel aufrufen, die eine Suspend-Funktion für den ViewmodelScope startet
– 2. Jan. 222
29. September 2020 um 9:26 Uhr
Andernfalls können Sie, wenn Sie einen Verweis auf eine AppCompatActivity haben, deren Lebenszyklusbereich verwenden
– 2. Jan. 222
29. September 2020 um 9:27 Uhr
Du meinst wie SomeScope.async { setLocation(getLocation()) }? Vielen Dank, das funktioniert tatsächlich, ich hätte nicht erwartet, dass es so einfach ist. Könnten Sie das bitte als Antwort kommentieren (damit ich diese Frage als gelöst markieren kann)?
– Nycta
30. September 2020 um 7:27 Uhr
Erstellen Sie einen Coroutinen-Bereich, der an den Lebenszyklus Ihres Composable gebunden ist, und verwenden Sie diesen Bereich, um Ihre Suspendierungsfunktion aufzurufen
suspend fun getLocation(): Location? { /* ... */ }
@Composable
fun F() {
// Returns a scope that's cancelled when F is removed from composition
val coroutineScope = rememberCoroutineScope()
val (location, setLocation) = remember { mutableStateOf<Location?>(null) }
val getLocationOnClick: () -> Unit = {
coroutineScope.launch {
val location = getLocation()
}
}
Button(onClick = getLocationOnClick) {
Text("detectLocation")
}
}
Ich habe auch die folgende Hilfsfunktion ausprobiert, um Entwicklerkollegen zu zwingen, Ausnahmen zu behandeln und schließlich den Status zu bereinigen (auch um den gleichen Code (vielleicht!?) etwas kürzer und (vielleicht!?) etwas lesbarer zu machen):
Sie können den viewModelScope eines ViewModel oder einen anderen Coroutine-Bereich verwenden.
Beispiel für die Löschaktion für ein Element aus LazyColumnFor, die einen Suspend-Aufruf erfordert, der von einem ViewModel verarbeitet wird.
class ItemsViewModel : ViewModel() {
private val _itemList = MutableLiveData<List<Any>>()
val itemList: LiveData<List<Any>>
get() = _itemList
fun deleteItem(item: Any) {
viewModelScope.launch(Dispatchers.IO) {
TODO("Fill Coroutine Scope with your suspend call")
}
}
}
@Composable
fun Example() {
val itemsVM: ItemsViewModel = viewModel()
val list: State<List<Any>?> = itemsVM.itemList.observeAsState()
list.value.let { it: List<Any>? ->
if (it != null) {
LazyColumnFor(items = it) { item: Any ->
ListItem(
item = item,
onDeleteSelf = {
itemsVM.deleteItem(item)
}
)
}
} // else EmptyDialog()
}
}
@Composable
private fun ListItem(item: Any, onDeleteSelf: () -> Unit) {
Row {
Text(item.toString())
IconButton(
onClick = onDeleteSelf,
icon = { Icons.Filled.Delete }
)
}
}
habe einen kurzen Blick darauf geworfen Quellcode der viewModelScope-Erweiterung. Könnte es ohne ViewModel nur mit verwendet werden? val scope = remember { CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate) } und dann onActive { onDispose { scope.cancel() } }?
– Nycta
1. Okt. 2020 um 5:33
Nicht großartig, man weiß nicht wirklich, wann die Operation endet. Verwenden Sie einfach „rememberCoroutinesScope()“ und verwandeln Sie „deleteItem()“ in eine Suspendierungsfunktion
– Hey Hey Hey
14. November 2020 um 16:18 Uhr
Ich stimme @heyheyhey zu, wir wissen nicht, wann das Composable aufgerufen wird, es wird möglicherweise beliebig oft abgerufen, daher ist es besser, es zu verwenden rememberCoroutineScope über viewModelScope
– GTXtreme
27. Mai 2022 um 4:34
14526800cookie-checkWie rufe ich Kotlin-Coroutine in zusammensetzbaren Funktionsrückrufen auf?yes
Sie können eine Funktion eines ViewModel aufrufen, die eine Suspend-Funktion für den ViewmodelScope startet
– 2. Jan. 222
29. September 2020 um 9:26 Uhr
Andernfalls können Sie, wenn Sie einen Verweis auf eine AppCompatActivity haben, deren Lebenszyklusbereich verwenden
– 2. Jan. 222
29. September 2020 um 9:27 Uhr
Du meinst wie
SomeScope.async { setLocation(getLocation()) }
? Vielen Dank, das funktioniert tatsächlich, ich hätte nicht erwartet, dass es so einfach ist. Könnten Sie das bitte als Antwort kommentieren (damit ich diese Frage als gelöst markieren kann)?– Nycta
30. September 2020 um 7:27 Uhr