lifecycleScope — چیست، پیوند با Lifecycle و کار در Android

نویسنده: IT Sectr منتشر شده: 2026-06-23 زمان مطالعه: 9 دقیقه

lifecycleScope — یک CoroutineScope داخلی از کتابخانهٔ androidx.lifecycle است که به چرخهٔ حیات Activity، Fragment یا هر LifecycleOwner متصل می‌شود و هنگام نابودی کامپوننت به‌طور خودکار کوروتین‌ها را لغو می‌کند. به گفتهٔ Google Android Developers, 2025، lifecycleScope امکان اجرای ایمن کوروتین‌های متصل به لایهٔ UI را بدون خطر اجرای کد پس از نابودی Activity یا Fragment فراهم می‌کند. scope با ورود LifecycleOwner به حالت DESTROYED به‌طور خودکار لغو می‌شود.

نکات اصلی

  • lifecycleScope — CoroutineScope از lifecycle-runtime-ktx، لغو شونده در حالت DESTROYED Lifecycle
  • lifecycleScope.launch — راه‌اندازی کوروتینی که هنگام نابودی LifecycleOwner به‌طور خودکار لغو می‌شود
  • launchWhenStarted / launchWhenResumed — روش‌های منسوخ شده، جایگزین شده با repeatOnLifecycle
  • repeatOnLifecycle — API مدرن برای راه‌اندازی کوروتین‌هایی که وضعیت خاص Lifecycle را دنبال می‌کنند
  • Dispatchers.Main.immediate — توزیع‌کنندهٔ پیش‌فرض برای lifecycleScope

lifecycleScope در Android چیست؟

lifecycleScope — یک ویژگی توسعه‌ای بر روی رابط LifecycleOwner (Activity، Fragment، Service) است که یک CoroutineScope آماده و متصل به چرخهٔ کامل حیات کامپوننت ارائه می‌دهد. هنگامی که LifecycleOwner به حالت DESTROYED می‌رسد، lifecycleScope به‌طور خودکار همهٔ کوروتین‌های فعال را لغو می‌کند.

kotlin
// در Fragment یا Activity
lifecycleScope.launch {
    delay(1000)
    showSnackbar("سلام!")
}

برخلاف viewModelScope، lifecycleScope در هر بار نابودی LifecycleOwner — از جمله چرخش صفحه — لغو می‌شود. این آن را برای عملیاتی که فقط باید تا زمانی که صفحهٔ خاصی قابل مشاهده است زنده بمانند ایده‌آل می‌کند.

کجا lifecycleScope در دسترس است

lifecycleScope در هر جایی که LifecycleOwner وجود دارد در دسترس است:

  • Activity — AppCompatActivity از LifecycleOwner ارث‌بری می‌کند
  • Fragment — Fragment از LifecycleOwner ارث‌بری می‌کند
  • LifecycleService — سرویس با چرخهٔ حیات
  • ProcessLifecycleOwner — چرخهٔ حیات کل برنامه
  • LifecycleOwner سفارشی — هر شیء که LifecycleOwner را پیاده‌سازی می‌کند

چگونه lifecycleScope کار می‌کند: Lifecycle و لغو خودکار

مکانیسم لغو خودکار lifecycleScope بر اساس اشتراک رویدادهای Lifecycle است. هنگامی که Lifecycle از CREATED به DESTROYED پایین می‌آید، scope لغو می‌شود.

وضعیت‌های Lifecycle

وضعیتتوضیحScope فعال
CREATEDLifecycleOwner ایجاد شده، onCreate اجرا شدهبله
STARTEDLifecycleOwner قابل مشاهده (onStart)بله
RESUMEDLifecycleOwner در پیش‌زمینه (onResume)بله
DESTROYEDLifecycleOwner نابود شده (onDestroy)خیر (scope لغو شده)

ساختار داخلی lifecycleScope

lifecycleScope به عنوان CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate) ایجاد می‌شود و در داخل Lifecycle ذخیره می‌گردد. هنگام انتقال Lifecycle به حالت DESTROYED، scope.cancel() فراخوانی می‌شود. این مکانیسم از طریق LifecycleEventObserver پیاده‌سازی می‌شود که در اولین دسترسی به scope در رویدادهای چرخهٔ حیات مشترک می‌شود.

رفتار هنگام چرخش

هنگام چرخش صفحه، Activity نابود می‌شود (onDestroy) و دوباره ایجاد می‌گردد. lifecycleScope همراه با Activity قدیمی لغو می‌شود و یک نمونهٔ جدید از scope برای Activity جدید ایجاد می‌گردد. این تفاوت اساسی با viewModelScope است که در هنگام چرخش حفظ می‌شود.

API lifecycleScope: launch، launchWhen و repeatOnLifecycle

کتابخانهٔ lifecycle چندین روش برای راه‌اندازی کوروتین‌ها از طریق lifecycleScope ارائه می‌دهد. بیایید تکامل API را از روش‌های منسوخ به مدرن بررسی کنیم.

lifecycleScope.launch — راه‌اندازی پایه

ساده‌ترین روش — lifecycleScope.launch { ... }. کوروتین بلافاصله شروع می‌شود و در DESTROYED لغو می‌گردد. با این حال ممکن است حتی زمانی که UI قابل مشاهده نیست (مثلاً در پس‌زمینه پس از onStop) کد اجرا کند. این همیشه مطلوب نیست.

منسوخ شده: launchWhenCreated / launchWhenStarted / launchWhenResumed

این روش‌ها وقتی Lifecycle پایین‌تر از وضعیت مشخص شده می‌رفت اجرای کوروتین را متوقف می‌کردند و هنگام بازگشت از سر می‌گرفتند. اما آنها در lifecycle-runtime-ktx 2.6.0 به عنوان @Deprecated علامت‌گذاری شدند، زیرا:

  • کوروتین را لغو نمی‌کردند — فقط متوقف می‌کردند
  • منجر به انباشت کوروتین‌های معلق مصرف‌کنندهٔ حافظه می‌شدند
  • در تغییر سریع وضعیت‌ها شرایط رقابتی (race condition) ایجاد می‌کردند

API مدرن: repeatOnLifecycle

repeatOnLifecycle — روش توصیه شده توسط Google برای راه‌اندازی کوروتین‌های همگام‌سازی شده با چرخهٔ حیات است. هر بار که Lifecycle به وضعیت مشخصی می‌رسد، کوروتین را لغو و دوباره راه‌اندازی می‌کند.

kotlin
lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.uiState.collect { state ->
            updateUI(state)
        }
    }
}

کوروتینی که به repeatOnLifecycle منتقل می‌شود وقتی Lifecycle به STARTED می‌رسد شروع می‌شود و وقتی به زیر STARTED می‌رود لغو می‌گردد. هنگام بازگشت به STARTED کوروتین دوباره از نو شروع می‌شود. این ایمن و کارآمد است — هیچ کوروتینی در حالت تعلیق باقی نمی‌ماند.

flowWithLifecycle — برای Flow

برای جمع‌آوری داده از Flow با در نظر گرفتن چرخهٔ حیات، عملگر flowWithLifecycle وجود دارد. این عملگر به‌طور خودکار جمع‌آوری را هنگام تغییر وضعیت Lifecycle متوقف و از سر می‌گیرد:

kotlin
viewModel.uiState
    .flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
    .onEach { state -> updateUI(state) }
    .launchIn(lifecycleScope)

عملگر flowWithLifecycle — مختصرترین راه برای اشتراک ایمن Flow در لایهٔ UI است.

نمونه‌های استفاده از lifecycleScope

سه سناریوی واقعی استفاده از lifecycleScope در برنامهٔ Android با Kotlin را بررسی می‌کنیم.

مثال ۱: اشتراک به‌روزرسانی‌های موقعیت مکانی فقط زمانی که صفحه قابل مشاهده است

kotlin
class MapFragment : Fragment() {

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                locationProvider.observeLocation().collect { loc ->
                    updateMapMarker(loc)
                }
            }
        }
    }
}

کوروتین وقتی فرگمنت قابل مشاهده می‌شود (STARTED) شروع می‌شود و وقتی از صفحه خارج می‌شود (STOPPED) لغو می‌گردد. اگر کاربر به برنامهٔ دیگری سوئیچ کند، به‌روزرسانی‌های موقعیت مکانی باتری مصرف نمی‌کنند.

مثال ۲: راه‌اندازی انیمیشن هنگام شروع فرگمنت

kotlin
lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.RESUMED) {
        animateFadeIn(titleView)
        delay(200)
        animateSlideUp(contentView)
    }
}

انیمیشن فقط زمانی شروع می‌شود که فرگمنت در پیش‌زمینه است (RESUMED). اگر کاربر در حین انیمیشن برنامه را ببندد، کوروتین لغو می‌شود و هنگام بازگشت انیمیشن دوباره شروع می‌گردد.

مثال ۳: همگام‌سازی دوره‌ای داده در صفحهٔ قابل مشاهده

kotlin
lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        while (isActive) {
            syncData()
            delay(30_000L)
        }
    }
}

داده‌ها هر ۳۰ ثانیه همگام‌سازی می‌شوند، اما فقط زمانی که صفحه قابل مشاهده است. isActive بررسی می‌کند که آیا کوروتین لغو نشده است، که خروج ایمن از حلقه را هنگام ترک صفحه تضمین می‌کند.

lifecycleScope در مقابل viewModelScope: سناریوهای کاربرد

هر دو scope به چرخهٔ حیات متصل هستند، اما به جنبه‌های مختلف آن. درک تفاوت برای معماری صحیح برنامه‌های Android حیاتی است.

تفاوت کلیدی

viewModelScope به ViewModel متصل است که از چرخش صفحه جان سالم به در می‌برد. lifecycleScope به LifecycleOwner (Activity/Fragment) متصل است که هنگام چرخش نابود و دوباره ایجاد می‌شود. این سناریوهای کاربرد آنها را تعیین می‌کند.

کی از lifecycleScope استفاده کنیم

  • اشتراک رویدادهای سیستمی (موقعیت مکانی، سنسورها، دوربین)
  • انیمیشن‌ها و افکت‌های UI متصل به یک صفحهٔ خاص
  • بارگذاری تکه‌تکهٔ داده با در نظر گرفتن قابلیت مشاهدهٔ صفحه
  • عملیاتی که باید با ترک صفحه متوقف شوند

کی از viewModelScope استفاده کنیم

  • بارگذاری داده از Repository
  • منطق کسب‌وکار که باید از چرخش جان سالم به در ببرد
  • ذخیره‌سازی و پردازش داده
  • هر عملیاتی که نتیجهٔ آن پس از چرخش مورد نیاز است

استفادهٔ ترکیبی

در عمل، ترکیب هر دو scope رایج است: viewModelScope داده را بارگذاری کرده و وضعیت را مدیریت می‌کند، lifecycleScope با در نظر گرفتن چرخهٔ حیات صفحه در Flow از ViewModel مشترک می‌شود. این تفکیک مسئولیت در توسعهٔ مدرن Android یک best practice محسوب می‌شود.

خطاهای رایج هنگام کار با lifecycleScope

چهار خطای رایجی که توسعه‌دهندگان هنگام استفاده از lifecycleScope مرتکب می‌شوند را بررسی می‌کنیم.

خطای ۱: استفاده از lifecycleScope به جای viewModelScope برای بارگذاری داده

اگر بارگذاری داده را در lifecycleScope.launch شروع کنید، هنگام چرخش صفحه کوروتین لغو می‌شود و داده باید دوباره بارگذاری شود. برای عملیات طولانی‌مدت از viewModelScope استفاده کنید. lifecycleScope — فقط برای وظایف مرتبط با UI.

خطای ۲: جمع‌آوری Flow بدون repeatOnLifecycle

فراخوانی مستقیم viewModel.someFlow.collect { ... } درون lifecycleScope.launch حتی زمانی که صفحه قابل مشاهده نیست به جمع‌آوری داده ادامه می‌دهد. این می‌تواند منجر به به‌روزرسانی UI در پس‌زمینه و سربار اضافی شود. همیشه از repeatOnLifecycle یا flowWithLifecycle استفاده کنید.

خطای ۳: فراموش کردن لغو هنگام ترک صفحه

اگرچه lifecycleScope در DESTROYED لغو می‌شود، کد پس از نقطهٔ تعلیق (suspend) ممکن است در لغو ناگهانی اجرا نشود. به اجرای کد پس از فراخوانی suspend اعتماد نکنید، مگر اینکه از NonCancellable استفاده کنید.

خطای ۴: استفاده از launchWhenStarted منسوخ به جای repeatOnLifecycle

launchWhenStarted و مشابه‌های آن کوروتین را لغو نمی‌کنند، فقط متوقف می‌کنند. اگر صفحه چندین بار بین پیش‌زمینه و پس‌زمینه جابجا شود، کوروتین فراخوانی‌های معوق را انباشته می‌کند. به repeatOnLifecycle مهاجرت کنید — این تنها راه صحیح همگام‌سازی با Lifecycle است.

سؤالات متداول

تفاوت بین lifecycleScope و GlobalScope چیست؟

lifecycleScope هنگام نابودی LifecycleOwner به‌طور خودکار لغو می‌شود. GlobalScope در تمام طول عمر برنامه زنده می‌ماند. کوروتین در lifecycleScope نمی‌تواند پس از نابودی کامپوننت UI را به‌روزرسانی کند، در GlobalScope می‌تواند که منجر به خطا می‌شود. همیشه در لایهٔ UI از lifecycleScope استفاده کنید.

آیا می‌توان از lifecycleScope در ViewModel استفاده کرد؟

خیر، ViewModel یک LifecycleOwner نیست، بنابراین lifecycleScope در آن در دسترس نیست. ViewModel از viewModelScope استفاده می‌کند. اگر کد باید در هر دو زمینه اجرا شود — منطق را با توابع suspend به use case یا repository منتقل کنید.

هنگام فراخوانی مجدد repeatOnLifecycle چه اتفاقی می‌افتد؟

هر فراخوانی repeatOnLifecycle یک کوروتین جدید ایجاد می‌کند که بلاک را هنگام رسیدن به وضعیت مشخص Lifecycle راه‌اندازی می‌کند. اگر repeatOnLifecycle دو بار برای یک وضعیت فراخوانی شود، هر دو بلاک مستقل اجرا می‌شوند. معمولاً یک بار فراخوانی در onViewCreated کافی است.

آیا می‌توان یک Dispatcher سفارشی برای lifecycleScope تنظیم کرد؟

نمی‌توان مستقیماً توزیع‌کنندهٔ lifecycleScope را تغییر داد — از Dispatchers.Main.immediate استفاده می‌کند. درون بلاک کوروتین می‌توانید از طریق withContext به توزیع‌کنندهٔ دیگری سوئیچ کنید. برای تست‌ها از TestDispatcher با LifecycleOwner استفاده کنید.

آیا lifecycleScope در onPause یا onDestroy لغو می‌شود؟

lifecycleScope هنگام ورود LifecycleOwner به حالت DESTROYED (پس از onDestroy) لغو می‌شود. فراخوانی‌های سادهٔ lifecycleScope.launch در onPause یا onStop لغو نمی‌شوند. برای توقف هنگام رفتن به پس‌زمینه از repeatOnLifecycle(STARTED) یا repeatOnLifecycle(RESUMED) استفاده کنید.

خلاصه

  • lifecycleScope — CoroutineScope متصل به LifecycleOwner که از طریق LifecycleEventObserver در DESTROYED به‌طور خودکار لغو می‌شود
  • Dispatchers.Main.immediate — توزیع‌کنندهٔ پیش‌فرض که به‌روزرسانی ایمن UI را بدون سوئیچ‌های اضافی تضمین می‌کند
  • repeatOnLifecycle — API مدرن برای راه‌اندازی کوروتین‌ها در وضعیت مشخص Lifecycle با لغو و راه‌اندازی مجدد خودکار
  • flowWithLifecycle — عملگر برای جمع‌آوری ایمن Flow از UI با در نظر گرفتن چرخهٔ حیات
  • launchWhenStarted منسوخ شده — به جای توقف، از repeatOnLifecycle استفاده کنید که کوروتین را لغو می‌کند نه اینکه متوقف کند
  • lifecycleScope در مقابل viewModelScope — lifecycleScope برای عملیات UI (انیمیشن‌ها، موقعیت مکانی)، viewModelScope برای داده و منطق کسب‌وکار
  • چرخش صفحه — lifecycleScope در چرخش لغو می‌شود، viewModelScope حفظ می‌شود; بسته به وظیفه scope را انتخاب کنید

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید