Middle
Jakie możliwości oferuje Kotlin do pracy z operacjami asynchronicznymi?
sobes.tech AI
Odpowiedź od AI
Kotlin zapewnia korutyny (coroutines) do upraszczania operacji asynchronicznych, oferując lekkie wątki, które nie blokują głównego wątku.
Kluczowe możliwości:
- Funkcje zawieszenia: Funkcje ze słowem kluczowym
suspend, które mogą być zawieszone i wznowione. Nie blokują wątku, na którym są wykonywane.suspend fun fetchData(): String { delay(1000) // Symulacja długiej operacji return "Dane otrzymane" } - Budowniczy korutyn: Funkcje używane do uruchamiania korutyn:
launch: Uruchamia nową korutynę i zwracaJob(nieblokujące).GlobalScope.launch { println("Uruchomiono korutynę") }async: Uruchamia nową korutynę i zwracaDeferred<T>(blokuje przy wywołaniu.await()).val deferred = GlobalScope.async { fetchData() } // ... val result = deferred.await() // Oczekiwanie na wynikrunBlocking: Blokuje bieżący wątek do czasu zakończenia korutyny (używane w mostach między blokującym a nieblokującym kodem, np. w testach).runBlocking { val data = fetchData() println(data) }
- Kontekst korutyny: Zbiór elementów określających zachowanie korutyny, w tym
DispatcheriJob.Dispatcher: Określa wątek lub pulę wątków, na których wykonywana jest korutyna.
- Dispatchers: Wbudowane obiekty do zarządzania wątkami:
Dispatchers.Default: Wspólna pula wątków w tle.Dispatchers.IO: Optymalizowane dla wejścia/wyjścia (operacje dyskowe, sieciowe).Dispatchers.Main: Główny wątek UI (dla Androida, JavaFX itp.).Dispatchers.Unconfined: Uruchamia korutynę w bieżącym wątku, ale po zawieszeniu może wznowić ją w dowolnym wątku.
GlobalScope.launch(Dispatchers.IO) { // Wykonywane w wątku wejścia/wyjścia } - Strukturalna współbieżność: Zasada, zgodnie z którą korutyny mają rodzica (
CoroutineScope) i są automatycznie anulowane przy anulowaniu rodzica. Zapobiega wyciekom zasobów i upraszcza zarządzanie cyklem życia.// CoroutineScope automatycznie zarządza korutynami potomnymi val scope = CoroutineScope(Dispatchers.Default) val job = scope.launch { // ... } // Przy anulowaniu scope, wszystkie korutyny potomne są anulowane scope.cancel() - Kanały: Do bezpiecznego przesyłania danych między korutynami. Mogą być:
- Bez bufora: Odbiór następuje tylko po wysłaniu.
- Buforowane: Pozwala na wysłanie kilku elementów przed zablokowaniem.
- Konkatedowane: Przechowuje tylko ostatni wysłany element.
val channel = Channel<Int>() scope.launch { for (x in 1..5) channel.send(x) channel.close() } scope.launch { for (y in channel) println(y) } - Flow: Strumień danych, który może emitować wiele wartości asynchronicznie. Podobny do RxJava
Observable, ale lżejszy i zintegrowany z korutynami.fun simpleFlow(): Flow<Int> = flow { for (i in 1..3) { delay(100) emit(i) // Wysyłanie wartości } } runBlocking { simpleFlow().collect { value -> println(value) } // Konsumpcja wartości }
Funkcje te pozwalają pisać kod asynchroniczny w stylu imperatywnym, czyniąc go bardziej czytelnym i łatwiejszym w utrzymaniu w porównaniu do użycia callbacków lub Future.