Middle
Jak konfigurować i używać korutyn w projektach Kotlin?
sobes.tech AI
Odpowiedź od AI
Aby skonfigurować korutyny, należy dodać odpowiednią zależność do pliku build.gradle.
// build.gradle (moduł aplikacji)
dependencies {
//... inne zależności
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3") // Dla JVM, Android, JS, Native
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3") // Dla Android (jeśli potrzebny Dispatchers.Main)
}
Użycie korutyn obejmuje:
-
Zakres życia (Scope): Określenie zakresu, w którym korutyny będą wykonywane i zarządzać swoim cyklem życia.
GlobalScope: Zakres życia całej aplikacji, używać ostrożnie, ponieważ może prowadzić do wycieków pamięci.CoroutineScope: Tworzony jawnie, pozwala kontrolować anulowanie korutyn.- Predefiniowane zakresy w frameworkach (np.
lifecycleScopew Android ViewModel).
// Przykład z CoroutineScope val myScope = CoroutineScope(Dispatchers.Default + SupervisorJob()) // Tworzenie zakresu z Dispatcher i Job fun performBackgroundTask() { myScope.launch { // Uruchomienie korutyny // Długi proces obliczeniowy } } fun cancelAllTasks() { myScope.cancel() // Anulowanie wszystkich korutyn w zakresie } -
Twórcy korutyn (Builders): Funkcje do uruchamiania korutyn.
launch: Uruchamia korutynę, która nie zwraca wyniku jawnie (zwracaJob).async: Uruchamia korutynę, która zwraca wynik w postaciDeferred.
import kotlinx.coroutines.* suspend fun fetchData() = coroutineScope { // coroutineScope - builder dla strukturalnej konkurencji val data1 = async { networkCall1() } // async zwraca Deferred val data2 = async { networkCall2() } // ... przetwarzanie danych po ich otrzymaniu data1.await() // Pobranie wyniku z Deferred, powoduje uśpienie korutyny do zakończenia data2.await() } suspend fun networkCall1(): String { delay(1000) // Symulacja zapytania sieciowego return "Data 1" } suspend fun networkCall2(): String { delay(1500) return "Data 2" } fun startFetching() = runBlocking { // runBlocking - builder do blokowania bieżącego wątku (np. main lub testy) launch { // launch zwraca Job println("Fetching data...") fetchData() println("Data fetched!") } } -
Dispatcher (Dispatchers): Określają, na którym wątku lub puli wątków będzie wykonywana korutyna.
Dispatchers.Default: Dla zadań intensywnych CPU.Dispatchers.IO: Dla blokujących operacji I/O (dostęp do plików, sieć).Dispatchers.Main: Główny wątek (tylko dla Android i Swing/JavaFX).Dispatchers.Unconfined: Uruchamia korutynę w wywołującym wątku, uśpiewa się, a następnie wznowi w wątku, który wznowił wykonanie.
import kotlinx.coroutines.* fun simpleTask() { GlobalScope.launch(Dispatchers.IO) { // Wskazanie dispatcher // Wykonanie operacji I/O println("Running on thread: ${Thread.currentThread().name}") } } fun main() = runBlocking { launch(Dispatchers.Default) { println("Default thread: ${Thread.currentThread().name}") } launch(Dispatchers.Unconfined) { println("Unconfined thread 1: ${Thread.currentThread().name}") delay(100) // Uśpienie println("Unconfined thread 2: ${Thread.currentThread().name}") // Wznowienie w innym wątku (możliwe) } delay(200) // Czekanie na zakończenie korutyn } -
Funkcje zawieszające (Suspending functions): Funkcje oznaczone słowem kluczowym
suspend, które mogą być zawieszone i wznowione bez blokowania wątku. Mogą być wywoływane tylko z innych funkcji zawieszających lub z bloku korutyny. -
Obsługa anulowania i wyjątków: Korutyny obsługują strukturalne anulowanie i propagację wyjątków.
- Anulowanie:
import kotlinx.coroutines.* fun cancellableTask() = GlobalScope.launch { try { repeat(1000) { i -> println("Working $i ...") delay(100) // funkcja zawieszająca, która respektuje anulowanie } } catch (e: CancellationException) { println("Task was cancelled!") } finally { println("Cleaning up...") } } fun main() = runBlocking { val job = cancellableTask() delay(500) // Czekanie trochę job.cancelAndJoin() // Anulowanie i czekanie na zakończenie } - Wyjątki: W przypadku
launch, nieobsłużony wyjątek spowoduje upadek aplikacji (w Android domyślnie). W przypadkuasync, wyjątek zostanie rzucony podczas wywołaniaawait(). Dla bardziej granularnej kontroli używa sięCoroutineExceptionHandlerlubSupervisorJob.
import kotlinx.coroutines.* fun main() = runBlocking { val handler = CoroutineExceptionHandler { _, exception -> println("Caught exception: $exception") } val job = GlobalScope.launch(handler) { // Zastosowanie obsługi wyjątków throw IllegalStateException("Something went wrong") } job.join() // Czekanie na zakończenie } - Anulowanie: