Sobes.tech
Middle

Kaip konfigūruoti ir naudoti korutinas Kotlin projektuose?

sobes.tech AI

Atsakymas iš AI

Korutinų konfigūracija reikalauja atitinkamos priklausomybės pridėjimo į build.gradle failą:

// build.gradle (modulio dalis)
dependencies {
    //... kitos priklausomybės
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3") // JVM, Android, JS, Native
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3") // Android (jei reikalingas Dispatchers.Main)
}

Korutinų naudojimas apima:

  1. Gyvenimo ciklas (Scope): Apibrėžia, kur ir kaip vykdomos korutinės funkcijos ir kaip valdyti jų gyvavimo ciklą:

    • GlobalScope: Visos programos apimtimi, naudoti atsargiai, nes gali būti atminties nutekėjimas.
    • CoroutineScope: Aiškiai sukurtas, leidžia kontroliuoti atšaukimą.
    • Anksčiau apibrėžti lauko (scope) pavyzdžiai (pavyzdžiui, lifecycleScope Android ViewModel).
    // Pavyzdys su CoroutineScope
    val myScope = CoroutineScope(Dispatchers.Default + SupervisorJob()) // Sukuria scope su Dispatcher ir Job
    
    fun performBackgroundTask() {
        myScope.launch { // Korutinos paleidimas
            // Ilgas skaičiavimas
        }
    }
    
    fun cancelAllTasks() {
        myScope.cancel() // Atšaukia visas korutinas scope'e
    }
    
  2. Korutinų kūrėjai (Builders): Funkcijos korutinų paleidimui:

    • launch: Paleidžia korutiną, kuri negrąžina rezultato (grąžina Job).
    • async: Paleidžia korutiną, kuri grąžina rezultatą Deferred:
    import kotlinx.coroutines.*
    
    suspend fun fetchData() = coroutineScope { // coroutineScope - struktūrizuotos konkurencijos kūrėjas
        val data1 = async { networkCall1() } // async grąžina Deferred
        val data2 = async { networkCall2() }
    
        // Duomenų apdorojimas po jų gavimo
        data1.await() // Rezultato gavimas iš Deferred, sustabdo korutiną
        data2.await()
    }
    
    suspend fun networkCall1(): String {
        delay(1000) // Tinklo užklausos imitacija
        return "Data 1"
    }
    
    suspend fun networkCall2(): String {
        delay(1500)
        return "Data 2"
    }
    
    fun startFetching() = runBlocking { // runBlocking - blokuoja esantį srautą
        launch { // launch grąžina `Job`
            println("Fetching data...")
            fetchData()
            println("Data fetched!")
        }
    }
    
  3. Dispečeriai (Dispatchers): Nustato, kuriame sraute ar srautų grupėje bus vykdoma korutina:

    • Dispatchers.Default: CPU intensyviems darbams
    • Dispatchers.IO: Blokuojančioms I/O operacijoms
    • Dispatchers.Main: Pagrindinis srautas (tik Android ir Swing/JavaFX)
    • Dispatchers.Unconfined: Paleidžia korutiną iškvietusio srauto, vėliau atnaujina kitame sraute:
    import kotlinx.coroutines.*
    
    fun simpleTask() {
        GlobalScope.launch(Dispatchers.IO) { // Nustatymas dispečerio
            // I/O operacijos vykdymas
            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) // Miego
             println("Unconfined thread 2: ${Thread.currentThread().name}") // Atkūrimas kitame sraute
        }
        delay(200) // Laukiama korutinų pabaigos
    }
    
  4. Laukiamos funkcijos (Suspending functions): Funkcijos, pažymėtos suspend, kurios gali būti sustabdytos ir atnaujintos be srauto blokavimo:

  5. Atšaukimas ir išimčių apdorojimas: Korutinai palaiko struktūrizuotą atšaukimą ir išimčių plitimą:

    • Atšaukimas:
      import kotlinx.coroutines.*
      
      fun cancellableTask() = GlobalScope.launch {
          try {
              repeat(1000) { i ->
                  println("Working $i ...")
                  delay(100) // sustabdomoji funkcija, gerbianti atšaukimą
              }
          } catch (e: CancellationException) {
              println("Task was cancelled!")
          } finally {
              println("Cleaning up...")
          }
      }
      
      fun main() = runBlocking {
          val job = cancellableTask()
          delay(500) // Trumpo laiko laukimas
          job.cancelAndJoin() // Atšaukimas ir laukimas pabaigos
      }
      
    • Išimtys: launch-e — neapdorota išimtis sukels programos žlugdymą (Android pagal numatytuosius nustatymus). async-e — išimtis bus išmesta await() kvietimo metu. Daugiau kontrolės galima pasiekti naudojant CoroutineExceptionHandler arba SupervisorJob:
    import kotlinx.coroutines.*
    
    fun main() = runBlocking {
        val handler = CoroutineExceptionHandler { _, exception ->
            println("Caught exception: $exception")
        }
    
        val job = GlobalScope.launch(handler) { // Naudojant apdorotoją
            throw IllegalStateException("Something went wrong")
        }
        job.join() // Laukiama pabaigos
    }