Mirë se vini në udhëzuesin gjithëpërfshirës mbi Kotlin Coroutines! Në këtë seri artikujsh, unë do t'ju çoj në një udhëtim magjepsës, duke filluar nga bazat dhe gradualisht duke u thelluar në koncepte të avancuara. Në këtë artikull do të flasim për anulimin e korutinës. Pra, kapni filxhanin tuaj të preferuar të kafesë, rehatohuni dhe le të zhytemi thellë në botën e Coroutines.

TEMA TË MBULUARA NË KËTË KAPITULLI

  • Pse të anuloni një korutinë, cila është arsyeja?
  • Çfarë është një korutinë bashkëpunuese?
  • Si të shkruani një kod kooperativë?
  • funksionet job.cancel() dhe job.cancelAndJoin().
  • yield() dhe delay() funksionet pezulluese.
  • CancellationException dhe TimeoutCancellationException.
  • withContext(NonCancellable), withTimeout dhe withTimeoutOrNull ndërtues të korutinës
  • përmbledhje

Nevoja për anulim

Ninja: Korutinat janë të lira për sa i përket përdorimit të burimeve. Pse duhet t'i anulojmë ato, Mjeshtër? A do të ketë ndonjë ndikim, apo anulimi është kryesisht për lirimin e burimeve të mbajtura?🤨

Master: Haha, nuk ka të bëjë vetëm me lëshimin e burimeve të mbajtura, miku im. Supozoni një situatë ku po merrni të dhëna nga serveri dhe kërkon shumë kohë, do të ishte një përvojë e tmerrshme, apo jo? Pra, në këtë rast duhet të caktohet koha e specifikuar, tejkalimi i këtij kufiri korutinë do të anulohet dhe kështu marrja. Ka disa aspekte për t'u marrë parasysh. Le t'i hedhim një sy disa prej tyre shpejt -

  1. Ndërveprimi i përdoruesit: Nëse një përdorues fillon një veprim që kërkon një korutinë për të kryer një detyrë (p.sh. marrjen e të dhënave nga një server), anulimi i korutinës mund të jetë i nevojshëm nëse përdoruesi ndryshon mendje dhe lundron te një ekran tjetër.
  2. Time-out: Kur prisni një rezultat nga një korutinë, është një praktikë e mirë të caktoni një afat kohor. Nëse rezultati i pritur nuk arrin brenda kornizës kohore të specifikuar, korutina mund të anulohet për të parandaluar që sistemi të presë pafundësisht.
  3. Trajtimi i gabimeve: Nëse ndodh një gabim që e bën punën e korutinës në vazhdim të parëndësishme ose të pamundur për t'u përfunduar, anulimi i korutinës mund të parandalojë përpunimin e panevojshëm dhe përdorimin e burimeve.
  4. Ndryshimet e kontekstit: Nëse konteksti në të cilin u lançua një korutinë ndryshon (për shembull, komponenti i ndërfaqes së përdoruesit të lidhur është shkatërruar), anulimi i korutinës mund të ndihmojë në parandalimin e përplasjeve ose rrjedhjeve të burimeve (Master: Shok, duhet të kesh përdorur viewLifecycleOwner.lifecycleScope.launch { // Coroutine work here } brenda, ai anulon korutinën sipas ciklit të jetës).
  5. Anulimi i korutinës së prindit: Nëse një korutinë e prindit anulohet, shpesh është e dëshirueshme që të anulohen automatikisht të gjitha korutinat e fëmijës për të siguruar pastrimin e duhur dhe lirimin e burimeve.

Mjeshtri: Shpresoj, tani e dini nevojën e anulimit.

Ninja: Padyshim Master, njohuri të mahnitshme veçanërisht pika 4. Por Master, a ka ndonjë kusht apo parakusht për të anuluar një korutinë, apo ndonjë korutinë mund të anulohet?🤔

Mjeshtri: Pyetje e mirë mik, kushti është që një korutinë duhet të jetë bashkëpunuese, kjo është tema jonë e radhës.

Çfarë është një korutinë bashkëpunuese?

Mjeshtri: Më thuaj, Ninja, çfarë do të ndodhë nëse e ekzekutoj këtë kod?

fun main(args: Array<String>) = runBlocking {
    println("Hey program starts here")
    val job: Job = launch {
        for (i in 1..500) {
            print("$i ")
           Thread.sleep(50)
        }

    }
    delay(10)
    job.cancelAndJoin()
    println("\noops program ends here")
}

Ninja: Ajo që unë mendoj është, pasi korutina niset për të printuar 1 to 500, por anulohet pas 10 ms, kështu që duhet të printojë disa vlera dhe të anulohet.

Mjeshtër: Jo! do të printojë 1 deri në 500 plotësisht dhe më pas do të ndalojë. Këtu vjen koncepti i korutinave bashkëpunuese, kushtojini vëmendje:

Korutinat bashkëpunuese në Kotlin janë si miqtë që ndërrojnë kur luajnë. Kur një mik është i zënë, ata ndalojnë dhe e lënë shokun tjetër të bëjë diçka. Në këtë mënyrë, të dy miqtë mund të punojnë së bashku pa ndërprerë njëri-tjetrin. Në mënyrë të ngjashme, korutinat në Kotlin punojnë së bashku duke ndaluar kur presin të ndodhë diçka, duke lejuar korutinat e tjera të kryejnë detyrat e tyre. Kjo bën që programet të funksionojnë pa probleme dhe me efikasitet.

Ninja: Awkayy!!, por si të bëjmë një kooperativë korutine? Kodi që më dhatë më sipër ishte përdorimi i korutinës, çfarë e ndalon atë të bëhet bashkëpunues?

Mjeshtër: Përsëri pyetje e mirë, ka dy metoda për të kontrolluar dhe për të bërë një kooperativë korutine.
1. kotlinx.coroutines.*suspend funksionet: Coroutine është bashkëpunues vetëm kur përdor funksione pezullimi nga paketa kotlinx.coroutines.*. Për shembull: delay(), yield(), withContext(), withTimeout() etj. Këto funksione janë të anulueshme dhe vazhdojnë të kontrollojnë periodikisht nëse është anuluar apo jo. : Mjeshtër i madh!, a mund të kemi një shembull të tij, apo versionin e korrigjuar të kodit të mësipërm pls?

Mjeshtër: Sigurisht, ne mund të përdorim delay() ose yield() pasi i përkasin kotlinx.coroutines.*

fun main(args: Array<String>) = runBlocking {
    println("Hey program starts here")
    val job: Job = launch {
        for (i in 1..500) {
            print("$i ")
           delay(50)
        }

    }
    delay(10)
    job.cancelAndJoin()
    println("\noops program ends here")
}

"Kështu që këtu do të ndalet pas printimit të disa vlerave, pasi korutina anulohet pas një vonese të vogël."

2. isActiveflamuri:

  • Flamuri isActive është një veçori Boolean që disponohet brenda një korutine dhe përdoret për të kontrolluar nëse korutina është ende aktive apo është anuluar.
  • Flamuri isActive është i dobishëm kur dëshironi të kontrolloni periodikisht nëse një korutinë duhet të vazhdojë ekzekutimin e saj, veçanërisht në situatat kur dëshironi që korutina t'i përgjigjet anulimit.
  • Mbani mend se kur një korutinë anulohet, ajo e përhap automatikisht anulimin tek korutinat e saj fëmijë dhe flamuri isActive do të bëhet false. Megjithatë, flamuri isActive nuk është i garantuar të pasqyrojë menjëherë statusin e anulimit nëse jeni duke përdorur funksione pezullimi jobashkëpunuese që nuk kontrollojnë për anulim. Në raste të tilla, mund të dëshironi të përfshini kontrolle të qarta për isActive për të siguruar një përgjigje në kohë ndaj anulimit.

Shënim: Të gjitha pezullimet që nuk janë pjesë e kotlinx.coroutines.* janë funksion pezullues jobashkëpunues.

fun main(args: Array<String>) = runBlocking {
    println("Hey program starts here")
    val job: Job = launch(Dispatchers.Default) {
        for (i in 1..1500) {
            if (!isActive) {
                return @launch
            }
            print("$i ")
            Thread.sleep(1)
        }

    }
    delay(10)
    job.cancelAndJoin()
    println("\noops program ends here")
}

"Ndalon pasi të printohen vetëm disa vlera"

Ninxha: Amazinggg!! Mjeshtër!!, shpresoj se edhe lexuesit duhet të kenë ndjerë të njëjtën gjë. A kemi koncept përjashtimi në korutinë? se si mund të trajtohet, jam vërtet kurioz të di. Mjeshtër, ju lutem mund të më ndihmoni?

Mjeshtri: Po bëhesh më i pangopur djalosh, haha. Sa herë që anulohet një korutinë, funksionet pezulluese të anulueshme si yield() ose delay() hedhin CancellationException. Le të kemi një shembull të saj.

fun main(args: Array<String>) = runBlocking {
    println("Hey program starts here")
    val job: Job = launch(Dispatchers.Default) {
        try{
            for (i in 1..1500) {
                print("$i ")
                yield()
            }
        }catch (ex:CancellationException){
            println("\ncaught the exception ${ex.message}")
        }finally {
            println("finally block executed")
        }
    }
    job.cancelAndJoin()
    println("\noops program ends here")
}

"Kështu që këtu korutina u anulua pas printimit të pak vlerave dhe gjithashtu kapet Përjashtimi, i cili u hodh duke pezulluar funksionin e anulueshëm yield()”

Ninja: Shkëlqyeshëm!, Por çfarë do të ndodhë nëse përdorim funksionin pezullues të anulueshëm (yield() ose delay() ) në bllokun finally? A do të ekzekutohet më tej apo jo? pasi korutina e prindërve tashmë është anuluar.🤔

Mjeshtri: Vëzhgim i mirë! Meqenëse korutina mëmë është anuluar, funksioni i pezullimit në bllokun përfundimtar gjithashtu do të anulohet dhe nuk do të ekzekutohet më tej. Shiko-

fun main(args: Array<String>) = runBlocking {
    println("Hey program starts here")
    val job: Job = launch(Dispatchers.Default) {
        try{
            for (i in 1..1500) {
                print("$i ")
                yield()
            }
        }catch (ex:CancellationException){
            println("\ncaught the exception ${ex.message}")
        }finally {
            println("Finally block before suspending function")
            yield()
            println("finally block after suspending function")
        }
    }
    job.cancelAndJoin()
    println("\noops program ends here")
}

"Kodi pas yield() në bllokun finally nuk ekzekutohet pasi korutina mëmë është anuluar"

Ninja: Gotcha!!, por çfarë të bëni kur është e nevojshme të përdorni funksionin e pezullimit të anulueshëm në bllokun finally?

Mjeshtër: Hmm, mendo pak, ekzekutimi në bllokun finally u ndërpre për shkak të anulimit të korutinës së tij mëmë, apo jo? Pra, thjesht përdorni funksionin e pezullimit të anulueshëm në një korutinë tjetër, indirekt do të ndryshojmë korutinën e tij mëmë. Shiko-

fun main(args: Array<String>) = runBlocking {
    println("Hey program starts here")
    val job: Job = launch(Dispatchers.Default) {
        try {
            for (i in 1..1500) {
                print("$i ")
                yield()
            }
        } catch (ex: CancellationException) {
            println("\ncaught the exception ${ex.message}")
        } finally {
            withContext(NonCancellable) {
                println("Finally block before suspending function")
                yield()
                println("finally block after suspending function")
            }
        }
    }
    job.cancelAndJoin()
    println("\noops program ends here")
}

"Anulimi i korutinës mëmë nuk ka asnjë efekt në kodin e bllokut finally pasi u lançua me një korutinë tjetër"

Ninja: Shpjegim i mrekullueshëm Master🤩. Edhe një gjë, dua të shfaq mesazhin e personalizuar Exception kur kapet Exception, a është e mundur?

Master: Patjetër, ju mund të kaloni objektin e CancellationException me mesazhin tuaj të personalizuar si parametër në të në momentin e anulimit. Shiko-

  fun main(args: Array<String>) = runBlocking {
    println("Hey program starts here")
    val job: Job = launch(Dispatchers.Default) {
        try {
            for (i in 1..1500) {
                print("$i ")
                yield()
            }
        } catch (ex: CancellationException) {
            println("\nCaught the exception: ${ex.message}")
        } finally {
                println("finally block")
        }
    }
    delay(1)
    job.cancel(CancellationException("Hurray! My custom exception"))
    job.join()
    println("oops program ends here")
}

" job.cancel(CancellationException(“Hurray! My custom exception”)) një mesazh i personalizuar i kaluar në momentin e anulimit"

Ninja: Kuptohet në mënyrë perfekte!

Master: Po sigurisht, kjo është ajo që është tema jonë e ardhshme.

Kohëzgjatja në korutina

Kohëzgjatja është një mekanizëm që ju lejon të kufizoni sasinë e kohës që lejohet të ekzekutohet një korutinë. Nëse korutina kërkon më shumë se kohëzgjatja e specifikuar për të përfunduar ekzekutimin e saj, ajo do të anulohet automatikisht. Kjo është e dobishme për të parandaluar që korutinat të funksionojnë për një kohë të pacaktuar dhe të shkaktojnë probleme të performancës ose burimeve.

Ninja: Si ta përdorni/zbatoni këtë?

Master: Funksionet withTimeout dhe withTimeoutOrNull ofrohen nga biblioteka Kotlin Coroutine për të zbatuar afatet. Shiko-

fun main(args: Array<String>) = runBlocking {
    println("Hey program starts here")

    withTimeout(500){
        for(i in 1..500){
            print("$i.")
            delay(100)
        }
    }
    
    println("oops program ends here")
}

"Përjashtim u hodh pas 500 ms pasi koha e specifikuar ishte 500 ms"

Gjithashtu mund ta kapim duke përdorur bllokun e kapjes, shih-

fun main(args: Array<String>) = runBlocking {
    println("Hey program starts here")

    try{
        withTimeout(500) {
            for (i in 1..500) {
                print("$i.")
                delay(100)
            }
        }
    }catch (ex:CancellationException){
        println("\nCaught successfully: ${ex.message} ")
    }finally {
        println("Finally block executed")
    }

    println("oops program ends here")
}

"Përjashtimi u kap dhe arsyeja shtypet gjithashtu duke përdorur veçorinë e mesazhit"

Ninja: Kjo është e mrekullueshme, por për çfarë është withTimeoutOrNull? A kthehet null apo diçka e tillë?

Mater: Umm, ti ishe pothuajse afër. withTimeoutOrNull është gjithashtu një ndërtues i korutinës me funksion të skadimit, megjithatë nuk bën asnjë përjashtim, do të kthejë një vlerë nga korutina.
Pra, nëse vendosni një vlerë në fund, do të kthehet njësoj vetëm kur korutina është përfunduar brenda afatit të caktuar kohor, përndryshe do të kthehet null. Shiko-

  • Rasti 1: Korutina përfundon brenda afatit kohor
fun main(args: Array<String>) = runBlocking {
    println("Hey program starts here")
    val result = withTimeoutOrNull(500) {
        for (i in 1..500) {
            print("$i.")   
        }
        "returning from the coroutine"
    }
    println("oops program ends here")
}

“Shtypi vlerat deri në 500 brenda afatit kohor dhe ktheu mesazhin e përmendur në fund”

  • Rasti 2: Korutina nuk përfundon brenda afatit kohor
fun main(args: Array<String>) = runBlocking {
    println("Hey program starts here")
    val result = withTimeoutOrNull(500) {
        for (i in 1..500) {
            delay(100)
            print("$i.")
        }
        "returning from the coroutine"
    }
    println("\n$result")
    println("oops program ends here")
}

“Ndodhi time-out dhe në këtë rast kthehet null”.

Ninja: Shumë dashuri Mjeshtër!!, Gjithçka që shpjegove në gjuhë të thjeshtë me një shpjegim kaq të detajuar.

Mjeshtri: Haha! Faleminderit, shok, duke bërë gjithashtu një përmbledhje të shkurtër të të gjitha gjërave që diskutuam më lart këtu.

Përmbledhje

Në këtë kapitull të Masterclass Coroutines, ne eksploruam konceptin vendimtar të anulimit të korutinës dhe trajtimit të përjashtimeve. Ne u thelluam në arsyet e anulimit të korutinave, duke mbuluar ndërveprimin e përdoruesit, afatet kohore, trajtimin e gabimeve, ndryshimet e kontekstit dhe anulimin e korutinës prindërore. U shpjeguan korutinat bashkëpunuese, të cilat ndalojnë kur është e nevojshme, së bashku me përdorimin e funksioneve kotlinx.coroutines.* dhe flamurit isActive për të arritur bashkëpunimin. Ne shikuam trajtimin e përjashtimeve dhe eksploruam se si të përdorim yield() dhe delay() në blloqet e fundit. Për më tepër, ne zbuluam botën e ndërprerjeve kohore duke përdorur funksionet withTimeout dhe withTimeoutOrNull, duke diskutuar dallimet e tyre dhe aplikimet praktike. Ky udhëzues gjithëpërfshirës ofron një kuptim të thellë të mekanizmave të anulimit dhe përjashtimit të korutinave.

Faleminderit që lexuat! Shpresoj se ju ka pëlqyer artikulli dhe e keni gjetur të vlefshëm në rritjen e njohurive tuaja. Kjo ishte (kapitulli-3), dhe ka shumë më tepër për të eksploruar në kapitujt e ardhshëm të serisë. Qëndroni të sintonizuar për artikuj me cilësi të lartë që do të pasurojnë më tej kuptueshmërinë tuaj. Nëse keni pyetje të mëtejshme ose dëshironi të kontribuoni në diskutim, ju lutemi mos ngurroni të lini komentet tuaja më poshtë. Reagimet dhe angazhimi juaj vlerësohen shumë. Faleminderit edhe një herë, dhe gëzuar kodimin!

INIT KOTLIN :)

Masterclass Coroutines:

"Kapitulli-1 (Themeli i Korutinave)"

"Kapitulli-2 (Ndërtuesit e Korutinës)"

Kapitulli-3 (Anulimi i korutinave)

Kapitulli-4 (vjen së shpejti)

Kapitulli-5 (së shpejti)

Master- Gaurav Arora

Ninja- SUMIT KUMAR

Kodi burim - Github