Sobes.tech
Middle

Kuidas seadistada ja kasutada korutinasid Kotlin projektides?

sobes.tech AI

Vastus AI-lt

Korutini seadistamine nõuab sobiva sõltuvuse lisamist build.gradle faili:

// build.gradle (mooduli osa)
dependencies {
    //... teised sõltuvused
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3") // JVM, Android, JS, Native jaoks
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3") // Android jaoks (kui on vajalik Dispatchers.Main)
}

Korutinite kasutamine hõlmab:

  1. Elutsükkel (Scope): Määrab, kus ja kuidas korutined täidetakse ning kuidas nende elutsüklit hallata:

    • GlobalScope: Kõigi rakenduse ulatuses, kasutada ettevaatusega, kuna võib tekkida mälulekked.
    • CoroutineScope: Selgelt loodud, võimaldab tühistamist.
    • Eelnevalt määratletud vahemikud (näiteks lifecycleScope Android ViewModelis).
    // Näide CoroutineScope'iga
    val myScope = CoroutineScope(Dispatchers.Default + SupervisorJob()) // Scope loomine koos Dispatcher ja Job-iga
    
    fun performBackgroundTask() {
        myScope.launch { // Korutina käivitamine
            // Pikk arvutusprotsess
        }
    }
    
    fun cancelAllTasks() {
        myScope.cancel() // Kõigi korutinate tühistamine scope'is
    }
    
  2. Korutinate ehitajad (Builders): Funktsioonid korutinate käivitamiseks:

    • launch: Käivitab korutina, mis ei tagasta tulemust (tagastab Job).
    • async: Käivitab korutina, mis tagastab tulemuse Deferred-ina:
    import kotlinx.coroutines.*
    
    suspend fun fetchData() = coroutineScope { // coroutineScope - struktuuriline konkurentsi ehitaja
        val data1 = async { networkCall1() } // async tagastab Deferred
        val data2 = async { networkCall2() }
    
        // Andmete töötlemine pärast nende saamist
        data1.await() // Tulemus Deferred-ist, peatab korutina
        data2.await()
    }
    
    suspend fun networkCall1(): String {
        delay(1000) // Võrgu päringu imitatsioon
        return "Data 1"
    }
    
    suspend fun networkCall2(): String {
        delay(1500)
        return "Data 2"
    }
    
    fun startFetching() = runBlocking { // runBlocking - blokeerib praeguse voolu
        launch { // launch tagastab `Job`
            println("Fetching data...")
            fetchData()
            println("Data fetched!")
        }
    }
    
  3. Dispečerid (Dispatchers): Määravad, millises voolus või voolugrupis täidetakse korutina:

    • Dispatchers.Default: CPU-intensiivsete ülesannete jaoks
    • Dispatchers.IO: Blokeerivate I/O operatsioonide jaoks
    • Dispatchers.Main: Peamine vool (ainult Android ja Swing/JavaFX)
    • Dispatchers.Unconfined: Käivitab korutina kutsunud voolus, siis jätkub teises voolus:
    import kotlinx.coroutines.*
    
    fun simpleTask() {
        GlobalScope.launch(Dispatchers.IO) { // Dispečeri määramine
            // I/O operatsiooni täitmine
            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) // Magamine
             println("Unconfined thread 2: ${Thread.currentThread().name}") // Jätkub teises voolus
        }
        delay(200) // Korutinate lõpetamise ootamine
    }
    
  4. Ootavad funktsioonid (Suspending functions): Funktsioonid, millele on märgitud suspend, mis võivad peatuda ja jätkata ilma voolu blokeerimata:

  5. Tühistamine ja erandite töötlemine: Korutinatele on toetatud struktuuriline tühistamine ja erandite levitamine:

    • Tühistamine:
      import kotlinx.coroutines.*
      
      fun cancellableTask() = GlobalScope.launch {
          try {
              repeat(1000) { i ->
                  println("Working $i ...")
                  delay(100) // peatamise funktsioon, mis austab tühistamist
              }
          } catch (e: CancellationException) {
              println("Task was cancelled!")
          } finally {
              println("Cleaning up...")
          }
      }
      
      fun main() = runBlocking {
          val job = cancellableTask()
          delay(500) // Vähe ootamine
          job.cancelAndJoin() // Tühistamine ja lõpetamise ootamine
      }
      
    • Erandid: launch-is — järelevalveta erand põhjustab rakenduse kokkuvarisemise (Androidis vaikimisi). async-is — erand visatakse await()-i kutsumisel. Rohkem kontrolli saab teha kasutades CoroutineExceptionHandler või SupervisorJob:
    import kotlinx.coroutines.*
    
    fun main() = runBlocking {
        val handler = CoroutineExceptionHandler { _, exception ->
            println("Caught exception: $exception")
        }
    
        val job = GlobalScope.launch(handler) { // Kasutades töötlejat
            throw IllegalStateException("Something went wrong")
        }
        job.join() // Ootab lõpetamist
    }