Sobes.tech
Middle

როგორ დავაყენოთ და გამოვიყენოთ კორუტინები Kotlin პროექტებში?

sobes.tech AI

პასუხი AI-სგან

კორუტინების კონფიგურაცია მოითხოვს შესაბამის დამოკიდებულებას build.gradle ფაილში:

// build.gradle (პროექტის მოდული)
dependencies {
    //... სხვა დამოკიდებულებები
    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-ისთვის (თუ საჭიროა Dispatchers.Main)
}

კორუტინების გამოყენება მოიცავს:

  1. ცხოვრების ციკლი (Scope): განსაზღვრავს, სად და როგორ შესრულდება კორუტინები და როგორ მართავს მათ სიცოცხლის ციკლს:

    • GlobalScope: მთელი აპლიკაციისთვის, გამოიყენოს ფრთხილად, რადგან მეხსიერების ლიკვიდაცია შესაძლებელია.
    • CoroutineScope: აშკარად შექმნილი, საშუალებას აძლევს გაუქმება.
    • ფრემვორკების წინასწარ განსაზღვრული სივრცეები (მაგალითად, lifecycleScope Android ViewModel-ში).
    // მაგალითი CoroutineScope-ით
    val myScope = CoroutineScope(Dispatchers.Default + SupervisorJob()) // შექმნა Scope-ით Dispatcher და Job
    
    fun performBackgroundTask() {
        myScope.launch { // კორუტინის დაწყება
            // ხანგრძლივი გამოთვლითი პროცესი
        }
    }
    
    fun cancelAllTasks() {
        myScope.cancel() // ყველა კორუტინის გაუქმება
    }
    
  2. კორუტინების შემქმნელები (Builders): ფუნქციები კორუტინების დასაწყებად:

    • launch: იწყებს კორუტინს, რომელიც არ აბრუნებს შედეგს (აბრუნებს Job-ს).
    • async: იწყებს კორუტინს, რომელიც აბრუნებს შედეგს Deferred-ის სახით:
    import kotlinx.coroutines.*
    
    suspend fun fetchData() = coroutineScope { // coroutineScope - სტრუქტურირებული კონკურენტობის ბილდერი
        val data1 = async { networkCall1() } // async აბრუნებს Deferred-ს
        val data2 = async { networkCall2() }
    
        // ... მონაცემების დამუშავება მიღების შემდეგ
        data1.await() // შედეგის მიღება Deferred-დან, სუპენს კორუტინას
        data2.await()
    }
    
    suspend fun networkCall1(): String {
        delay(1000) // ქსელური მოთხოვნის იმიტაცია
        return "Data 1"
    }
    
    suspend fun networkCall2(): String {
        delay(1500)
        return "Data 2"
    }
    
    fun startFetching() = runBlocking { // runBlocking - ბლოკავს მიმდინარე ნაკადს
        launch { // launch აბრუნებს `Job`
            println("Fetching data...")
            fetchData()
            println("Data fetched!")
        }
    }
    
  3. დისტეპჩერები (Dispatchers): განსაზღვრავს, რომელი ნაკადში ან ნაკადების ჯგუფში შესრულდება კორუტინა:

    • Dispatchers.Default: CPU-ინტენსიურ სამუშაოებისთვის
    • Dispatchers.IO: ბლოკირებადი I/O ოპერაციებისათვის
    • Dispatchers.Main: მთავარი ნაკადი (მხოლოდ Android და Swing/JavaFX)
    • Dispatchers.Unconfined: იწყება გამოძახებულ ნაკადში, შემდეგ განახლდება სხვა ნაკადში:
    import kotlinx.coroutines.*
    
    fun simpleTask() {
        GlobalScope.launch(Dispatchers.IO) { // დისტეპჩერის მითითება
            // 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) // ძილი
             println("Unconfined thread 2: ${Thread.currentThread().name}") // განახლება სხვა ნაკადში
        }
        delay(200) // კორუტინების დასრულების მოლოდინი
    }
    
  4. შეჩერებადი ფუნქციები (Suspending functions): suspend-ით მონიშნული ფუნქციები, რომლებიც შეიძლება შეჩერდეს და განახლდეს, არ ბლოკავენ ნაკადს:

  5. გაუქმება და გამონაკლისების მართვა: კორუტინებს მხარდაჭერა აქვთ სტრუქტურირებული გაუქმებისა და გამონაკლისების გავრცელებისთვის:

    • გაუქმება:
      import kotlinx.coroutines.*
      
      fun cancellableTask() = GlobalScope.launch {
          try {
              repeat(1000) { i ->
                  println("Working $i ...")
                  delay(100) // შეჩერებადი ფუნქცია, რომელიც პატივს სცემს გაუქმებას
              }
          } catch (e: CancellationException) {
              println("Task was cancelled!")
          } finally {
              println("Cleaning up...")
          }
      }
      
      fun main() = runBlocking {
          val job = cancellableTask()
          delay(500) // ცოტა ხნით მოლოდინი
          job.cancelAndJoin() // გაუქმება და დასრულების მოლოდინი
      }
      
    • გამონაკლისები: launch-ში — გაუქმებული გამონაკლისი გამოიწვევს აპლიკაციის ჩაქრობას (Android-ში — წინასწარ კონფიგურირებულია). async-ში — გამონაკლისი გამოიწვევს await()-ის დროს. უფრო დეტალური კონტროლი შესაძლებელია CoroutineExceptionHandler ან SupervisorJob-ით:
    import kotlinx.coroutines.*
    
    fun main() = runBlocking {
        val handler = CoroutineExceptionHandler { _, exception ->
            println("Caught exception: $exception")
        }
    
        val job = GlobalScope.launch(handler) { // გამკლავებლის გამოყენებით
            throw IllegalStateException("Something went wrong")
        }
        job.join() // დასრულების მოლოდინი
    }