Coroutine Builder — funcții Kotlin Coroutines care creează și lansează corutine, determinând modul lor de execuție. Constructorii launch, async, runBlocking și produce acoperă diferite scenarii: de la sarcini de fundal la calcule paralele cu returnarea rezultatului. Conform JetBrains, 2024, Coroutine Builder este baza modelului de corutine, asigurând concurență structurată și gestionarea ciclului de viață.
Principalele
Coroutine Builder — este o funcție de extensie Kotlin care primește CoroutineScope și un suspend-bloc, creând și lansând o nouă corutină. Fiecare constructor determină modul în care corutina va fi executată: cu sau fără returnarea rezultatului, cu blocarea firului sau asincron. Constructorii sunt puncte de intrare în modelul de corutine al limbajului.
Toți constructorii funcționează prin CoroutineScope, care gestionează ciclul de viață al corutinelor copil. La anularea scope-ului, toate corutinele lansate prin el sunt anulate automat — acesta este principiul concurenței structurate. Această abordare previne scurgerile de corutine și garantează o finalizare previzibilă.
import kotlinx.coroutines.*
fun main() = runBlocking {
// Constructorii rulează în interiorul CoroutineScope
val job = launch {
delay(1000L)
println("Lume!")
}
println("Salut,")
job.join()
}
Kotlin oferă patru constructori încorporați de corutine: launch, async, runBlocking și produce. Fiecare are propriul tip returnat și domeniul de aplicare. Pentru dezvoltarea mobilă pe Android, principalii sunt launch și async — funcționează neblocant și se integrează cu componentele arhitecturale.
| Constructor | Tip returnat | Blocare fir | Scenariu |
|---|---|---|---|
| launch | Job | Nu | Sarcini fire-and-forget |
| async | Deferred<T> | Nu | Calcule paralele |
| runBlocking | T | Da | Teste, funcția main |
| produce | ReceiveChannel<E> | Nu | Transmitere în flux (deprecated) |
Fiecare constructor acceptă parametri suplimentari: CoroutineStart (strategia de lansare), CoroutineContext (dispecer, excepții) și un bloc de cod denumit. Implicit, corutina este lansată imediat (CoroutineStart.DEFAULT).
launch — cel mai utilizat constructor în dezvoltarea Android. Lansează o corutină care nu returnează rezultat și returnează un obiect Job pentru gestionarea ciclului său de viață. Este alegerea ideală pentru operații unde este necesar doar un efect secundar: salvare în BD, trimitere analitică, actualizare UI.
Constructorul launch primește CoroutineScope, un CoroutineContext opțional și un suspend-bloc. Job returnat permite anularea corutinei, așteptarea finalizării sau verificarea stării.
val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
val job: Job = scope.launch(CoroutineStart.LAZY) {
val data = fetchFromNetwork()
saveToDatabase(data)
}
job.start()
job.join()
Parametrul CoroutineStart.LAZY amână lansarea până la apelarea explicită a start() sau join(). Acest lucru este util pentru inițializarea întârziată și lansarea condiționată. Pentru lansarea imediată standard se utilizează CoroutineStart.DEFAULT sau parametrul este omis.
async — constructor care returnează Deferred<T> — o promisiune asincronă a rezultatului. Apelul await() suspendă corutina până la obținerea rezultatului, fără a bloca firul. Acesta este mecanismul principal pentru sarcini paralele în corutinele Kotlin.
async este deosebit de eficient când trebuie executate mai multe operații independente simultan. Spre deosebire de apelarea secvențială a funcțiilor suspend, async lansează corutinele în paralel, reducând timpul total de execuție.
suspend fun fetchUserData(): UserData {
val deferred1 = CoroutineScope(Dispatchers.IO).async { api.getProfile() }
val deferred2 = CoroutineScope(Dispatchers.IO).async { api.getSettings() }
val deferred3 = CoroutineScope(Dispatchers.IO).async { api.getNotifications() }
return UserData(
profile = deferred1.await(),
settings = deferred2.await(),
notifications = deferred3.await()
)
}
Deferred moștenește din Job, deci async suportă toate operațiile ciclului de viață: anulare, așteptare finalizare, gestionare excepții. La anularea scope-ului, corutinele copil Deferred sunt anulate automat.
runBlocking — singurul constructor care blochează firul curent până la finalizarea corutinei. Creează un nou CoroutineScope și lansează corutina transmisă, blocând firul apelant. Este utilizat în punctele de intrare main(), în teste și la integrarea cu cod blocking.
runBlocking este justificat în trei scenarii: punctul de intrare al aplicației (main), testele unitare ale funcțiilor suspend și integrarea cu biblioteci bazate pe callback-uri unde nu se poate folosi suspend. În codul de producție Android, utilizarea runBlocking pe firul principal nu este categoric recomandată.
class CoroutineTest {
@Test
fun `test suspend function`() = runBlocking {
val result = mySuspendFunction()
assertEquals("expected", result)
}
}
Pentru teste se recomandă utilizarea kotlinx-coroutines-test cu TestCoroutineDispatcher în loc de runBlocking — aceasta asigură controlul timpului și evită blocările în mediul de testare.
Alegerea Coroutine Builder depinde de rezultatul returnat și de scenariul de execuție. Dacă operația nu necesită returnarea datelor — utilizați launch. Dacă este necesar rezultatul unei operații asincrone — async. runBlocking aplicați doar pentru bridging, iar produce înlocuiți-l cu Flow pentru fluxuri reactive.
În proiectele Android cu Kotlin Coroutines, perechea principală de constructori este launch și async. launch este utilizat în ViewModel și UseCases pentru lansarea corutinelor, iar async — pentru cereri paralele la rețea sau bază de date. Bibliotecile moderne (Ktor, Room) suportă deja funcții suspend, ceea ce minimizează necesitatea utilizării directe a lui async.
Întrebări frecvente
launch returnează Job și nu returnează rezultatul execuției, iar async returnează Deferred<T> — un obiect din care se poate obține rezultatul prin await(). launch este utilizat pentru operații fire-and-forget, async — pentru sarcini care returnează date.
Nu este recomandat. runBlocking pe firul principal cauzează ANR și blochează UI. Utilizați lifecycleScope.launch în interiorul Activity și Fragment — aceasta este o soluție încorporată fără blocări.
Constructorul launch returnează un obiect Job care permite controlarea ciclului de viață al corutinei: anulare (cancel), așteptare finalizare (join), verificare stare (isActive, isCompleted, isCancelled).
Deferred<T> — este o promisiune asincronă a rezultatului, returnată de constructorul async. Moștenește din Job și adaugă metodele await() pentru obținerea rezultatului, getCompleted() pentru acces neblocant și getCompletionExceptionOrNull() pentru verificarea excepției.
Utilizați parametrul CoroutineStart.LAZY: scope.launch(start = CoroutineStart.LAZY) { ... }. Apoi apelați job.start() sau job.join() pentru lansarea efectivă. Acest lucru este util pentru inițializarea întârziată și executarea condiționată a corutinelor.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și