Coroutine Builder — توابع Kotlin Coroutines هستند که کوروتینها را ایجاد و اجرا میکنند و نحوه اجرای آنها را تعیین میکنند. سازندههای launch، async، runBlocking و produce سناریوهای مختلفی را پوشش میدهند: از وظایف پسزمینه تا محاسبات موازی با بازگشت نتیجه. به گفته JetBrains, 2024، Coroutine Builder اساس مدل کوروتین است و همزمانی ساختاریافته و مدیریت چرخه عمر را فراهم میکند.
نکات اصلی
Coroutine Builder — تابع توسعهای Kotlin است که CoroutineScope و suspend-block را میپذیرد و یک کوروتین جدید ایجاد و اجرا میکند. هر سازنده تعیین میکند که کوروتین چگونه اجرا شود: با بازگشت نتیجه یا بدون آن، با مسدود کردن رشته یا به صورت ناهمگام. سازندهها نقاط ورود به مدل کوروتین در زبان هستند.
همه سازندهها از طریق CoroutineScope کار میکنند که چرخه عمر کوروتینهای فرزند را مدیریت میکند. هنگام لغو scope، تمام کوروتینهای اجرا شده از طریق آن به طور خودکار لغو میشوند — این اصل همزمانی ساختاریافته است. این رویکرد از نشت کوروتینها جلوگیری میکند و پایانپذیری قابل پیشبینی را تضمین میکند.
import kotlinx.coroutines.*
fun main() = runBlocking {
// سازندهها در داخل CoroutineScope کار میکنند
val job = launch {
delay(1000L)
println("جهان!")
}
println("سلام،")
job.join()
}
Kotlin چهار سازنده داخلی کوروتین ارائه میدهد: launch، async، runBlocking و produce. هر کدام نوع بازگشتی و حوزه کاربرد خود را دارند. برای توسعه موبایل Android، اصلیترین آنها launch و async هستند — آنها به صورت غیرمسدودکننده کار میکنند و با اجزای معماری ادغام میشوند.
| سازنده | نوع بازگشتی | مسدود کردن رشته | سناریو |
|---|---|---|---|
| launch | Job | خیر | وظایف fire-and-forget |
| async | Deferred<T> | خیر | محاسبات موازی |
| runBlocking | T | بله | تستها، تابع main |
| produce | ReceiveChannel<E> | خیر | انتقال جریانی (deprecated) |
هر سازنده پارامترهای اضافی میپذیرد: CoroutineStart (استراتژی اجرا)، CoroutineContext (توزیعکننده، استثناها) و بلوک کد نامگذاری شده. به طور پیشفرض کوروتین بلافاصله اجرا میشود (CoroutineStart.DEFAULT).
launch — پرکاربردترین سازنده در توسعه Android است. کوروتینی را اجرا میکند که نتیجه برنمیگرداند و شی Job را برای مدیریت چرخه عمر آن برمیگرداند. این انتخاب ایدهآل برای عملیاتی است که فقط به اثر جانبی نیاز دارند: ذخیره در پایگاه داده، ارسال تحلیل، بهروزرسانی UI.
سازنده launch CoroutineScope، CoroutineContext اختیاری و suspend-block را میپذیرد. Job بازگشتی به شما اجازه میدهد کوروتین را لغو کنید، منتظر اتمام آن بمانید یا وضعیت آن را بررسی کنید.
val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
val job: Job = scope.launch(CoroutineStart.LAZY) {
val data = fetchFromNetwork()
saveToDatabase(data)
}
job.start()
job.join()
پارامتر CoroutineStart.LAZY اجرا را تا فراخوانی صریح start() یا join() به تأخیر میاندازد. این برای مقداردهی اولیه تأخیری و اجرای شرطی مفید است. برای اجرای فوری استاندارد از CoroutineStart.DEFAULT استفاده میشود یا پارامتر حذف میگردد.
async — سازندهای که Deferred<T> را برمیگرداند — وعده ناهمگام نتیجه. فراخوانی await() کوروتین را تا دریافت نتیجه متوقف میکند، بدون اینکه رشته را مسدود کند. این مکانیزم اصلی برای وظایف موازی در کوروتینهای Kotlin است.
async به ویژه زمانی مؤثر است که نیاز به انجام چندین عملیات مستقل به طور همزمان باشد. برخلاف فراخوانی ترتیبی توابع suspend، async کوروتینها را به صورت موازی اجرا میکند و زمان کل اجرا را کاهش میدهد.
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 از Job ارثبری میکند، بنابراین async از تمام عملیات چرخه عمر پشتیبانی میکند: لغو، انتظار برای اتمام، مدیریت استثناها. هنگام لغو scope، کوروتینهای فرزند Deferred به طور خودکار لغو میشوند.
runBlocking — تنها سازندهای است که رشته جاری را تا پایان کوروتین مسدود میکند. CoroutineScope جدیدی ایجاد میکند و کوروتین ارسال شده را اجرا میکند و رشته فراخوان را مسدود میکند. در نقاط ورود main()، در تستها و در ادغام با کد blocking استفاده میشود.
runBlocking در سه سناریو توجیه میشود: نقطه ورود برنامه (main)، تستهای واحد توابع suspend و ادغام با کتابخانههای callback-based که در آنها نمیتوان از suspend استفاده کرد. در کد تولید Android، استفاده از runBlocking در رشته اصلی قطعاً توصیه نمیشود.
class CoroutineTest {
@Test
fun `test suspend function`() = runBlocking {
val result = mySuspendFunction()
assertEquals("expected", result)
}
}
برای تستها توصیه میشود به جای runBlocking از kotlinx-coroutines-test با TestCoroutineDispatcher استفاده کنید — این کنترل زمان را فراهم میکند و از قفلشدگی در محیط تست جلوگیری میکند.
انتخاب Coroutine Builder به نتیجه بازگشتی و سناریوی اجرا بستگی دارد. اگر عملیات نیاز به بازگشت داده ندارد — از launch استفاده کنید. اگر نتیجه عملیات ناهمگام مورد نیاز است — async. runBlocking را فقط برای bridging به کار ببرید و produce را برای جریانهای واکنشی با Flow جایگزین کنید.
در پروژههای Android با Kotlin Coroutines، جفت اصلی سازندهها launch و async هستند. launch در ViewModel و UseCases برای اجرای کوروتینها استفاده میشود و async — برای درخواستهای موازی به شبکه یا پایگاه داده. کتابخانههای مدرن (Ktor, Room) قبلاً از توابع suspend پشتیبانی میکنند که نیاز به استفاده مستقیم از async را به حداقل میرساند.
سوالات متداول
launch Job برمیگرداند و نتیجه اجرا را برنمیگرداند، در حالی که async Deferred<T> — شیئی که میتوان از طریق await() نتیجه را از آن دریافت کرد — برمیگرداند. launch برای عملیات fire-and-forget استفاده میشود، async — برای وظایفی که داده برمیگردانند.
توصیه نمیشود. runBlocking در رشته اصلی باعث ANR میشود و UI را مسدود میکند. از lifecycleScope.launch در داخل Activity و Fragment استفاده کنید — این راهحل داخلی بدون قفلشدگی است.
سازنده launch شی Job را برمیگرداند که به شما امکان میدهد چرخه عمر کوروتین را کنترل کنید: لغو (cancel)، انتظار برای اتمام (join)، بررسی وضعیت (isActive, isCompleted, isCancelled).
Deferred<T> — وعده ناهمگام نتیجه است که توسط سازنده async بازگردانده میشود. از Job ارثبری میکند و متدهای await() برای دریافت نتیجه، getCompleted() برای دسترسی غیرمسدودکننده و getCompletionExceptionOrNull() برای بررسی استثنا را اضافه میکند.
از پارامتر CoroutineStart.LAZY استفاده کنید: scope.launch(start = CoroutineStart.LAZY) { ... }. سپس برای اجرای واقعی job.start() یا job.join() را فراخوانی کنید. این برای مقداردهی اولیه تأخیری و اجرای شرطی کوروتینها مفید است.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید