چرخه حیات فعالیت

وقتی کاربر در برنامه‌تان پیمایش می‌کند، از آن خارج می‌شود، و به آن برمی‌گردد، Activityنمونه‌های برنامه‌تان در چرخه عمر خود از وضعیت‌های مختلفی عبور می‌کنند. کلاس Activity تعدادی برگشت تماس ارائه می‌دهد که به فعالیت اجازه می‌دهد وقتی وضعیت تغییر می‌کند یا سیستم درحال ایجاد، توقف، یا ازسرگیری فعالیت یا ازبین بردن فرایندی است که فعالیت در آن قرار دارد، مطلع شود.

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

هر تماس برگشتی به شما امکان می‌دهد کار خاصی را که برای تغییر وضعیت معینی مناسب است انجام دهید. انجام کار درست در زمان مناسب و مدیریت صحیح انتقال‌ها باعث می‌شود برنامه شما قوی‌تر و کارآمدتر شود. برای مثال، پیاده‌سازی خوب بازخوان‌های چرخه حیات می‌تواند به برنامه شما کمک کند از موارد زیر اجتناب کند:

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

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

سپس به‌طور خلاصه رابطه بین وضعیت فعالیت و آسیب‌پذیری فرایند دربرابر بسته شدن توسط سیستم را معرفی می‌کند. درنهایت، به چندین موضوع مرتبط با گذار بین وضعیت‌های فعالیت می‌پردازد.

برای کسب اطلاعات درباره مدیریت چرخه‌های حیات، ازجمله راهنمایی درباره روال‌های مطلوب، به چرخه حیات در Jetpack Compose و ذخیره وضعیت‌های رابط کاربری مراجعه کنید. برای آشنایی با نحوه طراحی یک برنامه قوی و با کیفیت تولید بااستفاده از فعالیت‌ها در ترکیب با عناصر معماری، به راهنمای معماری برنامه مراجعه کنید.

مفاهیم چرخه حیات فعالیت

برای پیمایش گذارها بین مراحل چرخه حیات فعالیت، کلاس Activity مجموعه اصلی از شش برگشت ارائه می‌دهد: onCreate، onStart، onResume، onPause، onStop، و onDestroy. سیستم هریک از این برگشتی‌ها را وقتی فعالیت وارد وضعیت جدیدی می‌شود فراخوانی می‌کند.

شکل ۱ نمایشی تصویری از این الگو ارائه می‌دهد.

شکل ۱. تصویر ساده‌شده‌ای از چرخه حیات فعالیت.

وقتی کاربر شروع به ترک فعالیت می‌کند، سیستم روش‌هایی را برای ازهم بازکردن فعالیت فرا می‌خواند. در برخی موارد، فعالیت فقط به‌طور جزئی برچیده می‌شود و همچنان در حافظه باقی می‌ماند، مثلاً وقتی کاربر به برنامه دیگری می‌رود. در این موارد، فعالیت همچنان می‌تواند به پیش‌زمینه برگردد.

اگر کاربر به فعالیت برگردد، از جایی که کاربر آن را رها کرده بود ازسر گرفته می‌شود. با چند استثنا، برنامه‌ها محدود شده‌اند از اینکه فعالیت‌ها را هنگام اجرا در پس‌زمینه شروع کنند.

احتمال اینکه سیستم یک فرایند معین را به‌همراه فعالیت‌های موجود در آن متوقف کند، به وضعیت فعالیت در آن زمان بستگی دارد. برای اطلاعات بیشتر درباره رابطه بین وضعیت و آسیب‌پذیری دربرابر بیرون انداخته شدن، به بخش درباره وضعیت فعالیت و بیرون انداخته شدن از حافظه مراجعه کنید.

بسته به پیچیدگی فعالیتتان، احتمالاً نیازی نیست همه روش‌های چرخه حیات را پیاده‌سازی کنید. بااین‌حال، مهم است که هریک از آن‌ها را درک کنید و آن‌هایی را که باعث می‌شوند برنامه شما مطابق انتظار کاربران عمل کند پیاده‌سازی کنید.

‫Compose و چرخه حیات

در «نوشتن»، از قرار دادن منطق کسب‌وکار یا تنظیم دستی ناظر مستقیماً در داخل برگشتی‌های فعالیت مثل onStart یا onResume خودداری کنید. به‌جای آن، از جلوه‌های آگاه از چرخه حیات و ناظران آگاه از وضعیت استفاده کنید که به‌طور خودکار با حضور «میانای کاربری» در صفحه‌نمایش هماهنگ می‌شوند.

  • مجموعه آگاه از چرخه زندگی: از collectAsStateWithLifecycle برای مصرف کردن جاری‌سازی‌ها از ViewModel استفاده کنید. این API وقتی واسط کاربر وارد وضعیت «شروع‌شده» می‌شود به‌طور خودکار شروع به جمع‌آوری می‌کند و وقتی به پس‌زمینه می‌رود متوقف می‌شود، و از مصرف غیرضروری منابع جلوگیری می‌کند. پس‌از جمع‌آوری جریان به‌عنوان وضعیت، می‌توانید از LifecycleEffects برای اجرای کد هنگام وقوع رویداد «چرخه حیات» استفاده کنید.
  • جریان منطق: بااستفاده از این APIها، رابط کاربری ازطریق درخت ترکیب به‌طور طبیعی به وضعیت چرخه حیات واکنش نشان می‌دهد و تضمین می‌کند که منطق کسب‌وکار فقط زمانی اجرا شود که کاربر به‌طور فعال با عنصر در تعامل باشد.

برای اطلاعات بیشتر درباره Compose و چرخه زندگی، به چرخه زندگی در Jetpack Compose مراجعه کنید.

فراخوانی‌های چرخه حیات

این بخش اطلاعات مفهومی و پیاده‌سازی درباره روش‌های برگشتی مورداستفاده درطول چرخه حیات فعالیت ارائه می‌دهد.

برخی‌از کنش‌ها در روش‌های چرخه حیات فعالیت قرار می‌گیرند. بااین‌حال، کدی را که کنش‌های یک عنصر وابسته را در عنصر پیاده‌سازی می‌کند، به‌جای روش چرخه حیات فعالیت، در عنصر قرار دهید. برای دستیابی به این هدف، باید مؤلفه وابسته را از چرخه حیات آگاه کنید. برای آشنایی با نحوه آگاه کردن اجزای وابسته از چرخه حیات، چرخه حیات در Jetpack Compose را ببینید.

onCreate

باید این برگشت تماس را که وقتی سیستم برای اولین‌بار فعالیت را ایجاد می‌کند اجرا می‌شود پیاده‌سازی کنید. پس‌از ایجاد فعالیت، فعالیت وارد وضعیت ایجادشده می‌شود. در روش onCreate، منطق راه‌اندازی برنامه پایه را که فقط یک‌بار در طول عمر فعالیت اتفاق می‌افتد اجرا کنید.

برای مثال، پیاده‌سازی onCreate شما ممکن است داده‌ها را به فهرست‌ها پیوند دهد، فعالیت را با ViewModel مرتبط کند، و برخی‌از متغیرهای محدوده کلاس را نمونه‌سازی کند. این روش پارامتر savedInstanceState را دریافت می‌کند، که یک شیء Bundle حاوی وضعیت قبلاً ذخیره‌شده فعالیت است. اگر فعالیت قبلاً وجود نداشته باشد، مقدار Bundle object تهی است.

اگر مؤلفه آگاه به چرخه حیات دارید که به چرخه حیات فعالیت شما متصل است، رویداد ON_CREATE را دریافت می‌کند. روش حاشیه‌گذاری‌شده با @OnLifecycleEvent فراخوانده می‌شود تا عنصر آگاه از چرخه حیات بتواند هر کد راه‌اندازی موردنیاز برای وضعیت ایجادشده را اجرا کند.

مثال زیر نشان می‌دهد چگونه یک Text قابل ترکیب را در یک فعالیت با حداقل امکانات ادغام کنید:

class ExampleActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent { // In here, we can call composables!
            MaterialTheme {
                Greeting(name = "compose")
            }
        }
    }
}

@Composable
fun Greeting(name: String) {
    Text(text = "Hello $name!")
}

فعالیت شما در وضعیت «ایجادشده» باقی نمی‌ماند. پس‌از اینکه روش onCreate اجرا شد، فعالیت وارد حالت شروع‌شده می‌شود و سیستم روش‌های onStart و onResume را به‌سرعت پشت سر هم فرا می‌خواند.

onStart

وقتی فعالیت وارد وضعیت «شروع‌شده» می‌شود، سیستم onStart را فرا می‌خواند. این فراخوانی فعالیت را برای کاربر قابل‌مشاهده می‌کند زیرا برنامه برای فعالیت آماده می‌شود تا وارد پیش‌زمینه شود و تعاملی شود. برای مثال، این روش جایی است که کد نگهداری میانای کاربری در آن مقداردهی اولیه می‌شود.

وقتی فعالیت به وضعیت «شروع‌شده» منتقل می‌شود، هر عنصر آگاه از چرخه حیات که به چرخه حیات فعالیت مرتبط باشد رویداد ON_START را دریافت می‌کند.

روش onStart به‌سرعت تکمیل می‌شود و، مانند وضعیت «ایجادشده»، فعالیت در وضعیت «شروع‌شده» باقی نمی‌ماند. پس‌از پایان این تماس برگشتی، فعالیت وارد حالت ازسرگرفته‌شده می‌شود و سیستم روش onResume را فرا می‌خواند.

onResume

وقتی فعالیت وارد وضعیت «ازسرگرفته‌شده» می‌شود، به پیش‌زمینه می‌آید و سیستم کاربرگ onResume را فرا می‌خواند. این وضعیتی است که برنامه در آن با کاربر تعامل برقرار می‌کند. برنامه تا زمانی که اتفاقی بیفتد که تمرکز را از برنامه بردارد، در این وضعیت باقی می‌ماند، مثلاً دستگاه تماس تلفنی دریافت کند، کاربر به فعالیت دیگری پیمایش کند، یا صفحه دستگاه خاموش شود.

وقتی فعالیت به حالت «ازسرگرفته‌شده» منتقل می‌شود، هر مؤلفه آگاه از چرخه حیات که به چرخه حیات فعالیت مرتبط باشد رویداد ON_RESUME را دریافت می‌کند. در اینجا، عناصر چرخه حیات می‌توانند هر عملکردی را که باید درحالی‌که عنصر نمایان و در پیش‌زمینه است اجرا شود فعال کنند، مثلاً پیش‌نمایش دوربین را شروع کنند.

وقتی رویداد وقفه‌اندازی روی می‌دهد، فعالیت وارد وضعیت توقف موقت می‌شود و سیستم بازمانی onPause را فرا می‌خواند.

اگر فعالیت از حالت «موقتاً متوقف‌شده» به حالت «ازسرگرفته‌شده» برگردد، سیستم دوباره متد onResume را فرا می‌خواند. به همین دلیل، onResume را پیاده‌سازی کنید تا مؤلفه‌هایی را که درطول onPause منتشر می‌کنید مقداردهی اولیه کنید و هرگونه مقداردهی اولیه دیگری را که باید هر بار فعالیت وارد حالت «ازسرگیری» شود انجام دهید.

در اینجا نمونه‌ای از یک عنصر آگاه از چرخه حیات آورده شده است که وقتی عنصر رویداد ON_RESUME را دریافت می‌کند به دوربین دسترسی پیدا می‌کند:

class CameraComponent : LifecycleObserver {
    ...
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    fun initializeCamera() {
        if (camera == null) {
            getCamera()
        }
    }
    ...
}

کد قبلی دوربین را پس‌از اینکه LifecycleObserver رویداد ON_RESUME را دریافت کرد مقداردهی اولیه می‌کند. بااین‌حال، در حالت چندپنجره‌ای، فعالیت شما ممکن است حتی زمانی که در حالت «توقف موقت» است کاملاً قابل‌مشاهده باشد. برای مثال، وقتی برنامه در حالت چندپنجره‌ای است و کاربر روی پنجره‌ای که فعالیت شما در آن نیست ضربه می‌زند، فعالیت شما به حالت «مکث» می‌رود.

اگر می‌خواهید دوربین فقط زمانی فعال باشد که برنامه «ازسر گرفته شده» است (قابل‌مشاهده و فعال در پیش‌زمینه)، دوربین را پس‌از رویداد ON_RESUME که قبلاً نشان داده شد مقداردهی اولیه کنید. اگر می‌خواهید دوربین درحالی‌که فعالیت در حالت «مکث» است اما قابل‌مشاهده است (مثلاً در حالت چندپنجره‌ای) فعال بماند، دوربین را پس‌از رویداد ON_START مقداردهی اولیه کنید.

بااین‌حال، فعال بودن دوربین درحالی‌که فعالیتتان «موقتاً متوقف» است ممکن است دسترسی به دوربین را برای برنامه دیگری که در حالت چندپنجره‌ای «ازسر گرفته شده» است مسدود کند. گاهی لازم است دوربین را درحالی‌که فعالیتتان «متوقف» است فعال نگه دارید، اما اگر این کار را انجام دهید ممکن است تجربه کاربری کلی را مختل کند.

به همین دلیل، با دقت فکر کنید که در کدام مرحله از چرخه حیات مناسب‌ترین زمان برای کنترل منابع سیستم مشترک در زمینه حالت چند پنجره‌ای است. برای کسب اطلاعات بیشتر درباره پشتیبانی از حالت چندپنجره‌ای، به پشتیبانی از حالت چندپنجره‌ای مراجعه کنید.

صرف‌نظر از اینکه کدام رویداد آماده‌سازی را برای انجام عملیات مقداردهی اولیه انتخاب می‌کنید، حتماً از رویداد چرخه حیات مربوطه برای انتشار منبع استفاده کنید. اگر چیزی را پس‌از رویداد ON_START مقداردهی اولیه می‌کنید، آن را پس‌از رویداد ON_STOP آزاد یا خاتمه دهید. اگر پس‌از رویداد ON_RESUME مقداردهی اولیه می‌کنید، پس‌از رویداد ON_PAUSE آزاد کنید.

تکه کد قبلی کد مقداردهی اولیه دوربین را در یک عنصر آگاه از چرخه حیات قرار می‌دهد. درعوض می‌توانید این کد را مستقیماً در بازخوان‌های چرخه حیات فعالیت، مثل onStart و onStop، قرار دهید، اما این کار را توصیه نمی‌کنیم. افزودن این منطق به یک عنصر مستقل و آگاه از چرخه حیات به شما امکان می‌دهد بدون نیاز به تکرار کد، از این عنصر در چندین فعالیت استفاده مجدد کنید. برای آشنایی با نحوه ایجاد مؤلفه آگاه از چرخه حیات، به چرخه حیات در Jetpack Compose مراجعه کنید.

onPause

سیستم این روش را به‌عنوان اولین نشانه خروج کاربر از فعالیت شما فرا می‌خواند، اگرچه این فراخوانی همیشه به معنای ازبین رفتن فعالیت نیست. این نشان می‌دهد که فعالیت دیگر در پیش‌زمینه نیست، اما اگر کاربر در حالت چندپنجره‌ای باشد، همچنان قابل‌مشاهده است. چند دلیل برای اینکه یک فعالیت ممکن است وارد این وضعیت شود وجود دارد:

  • رویدادی که اجرای برنامه را قطع می‌کند، همان‌طور که در بخش مربوط به بازخوان onResume توضیح داده شده است، فعالیت فعلی را موقتاً متوقف می‌کند. این رایج‌ترین مورد است.
  • در حالت چندپنجره‌ای، فقط یک برنامه در هر زمان تمرکز دارد و سیستم همه برنامه‌های دیگر را موقتاً متوقف می‌کند.
  • باز شدن فعالیت جدید نیمه‌شفاف، مثل کادر گفتگو، فعالیتی را که می‌پوشاند موقتاً متوقف می‌کند. تا زمانی که فعالیت تا حدی قابل‌مشاهده باشد اما در کانون توجه نباشد، موقتاً متوقف می‌ماند.

وقتی فعالیتی به حالت «متوقف» منتقل می‌شود، هر عنصر آگاه از چرخه حیات که به چرخه حیات فعالیت مرتبط باشد رویداد ON_PAUSE را دریافت می‌کند. در اینجا عناصر چرخه حیات می‌توانند هر عملکردی را که نیاز نیست وقتی عنصر در پیش‌زمینه نیست اجرا شود متوقف کنند، مثلاً پیش‌نمایش دوربین را متوقف کنند.

از روش onPause برای موقتاً متوقف کردن یا اصلاح کردن عملیاتی که نمی‌توانند ادامه یابند، یا ممکن است در حالت میانه‌روی ادامه یابند، درحالی‌که Activity در حالت «موقتاً متوقف‌شده» است، و انتظار دارید که به‌زودی ازسر گرفته شوند استفاده کنید.

همچنین می‌توانید از روش onPause برای آزاد کردن منابع سیستم، دسترسی به حسگرها (مثل GPS)، یا هر منبعی که بر عمر باتری تأثیر می‌گذارد درحالی‌که فعالیتتان «متوقف» است و کاربر به آن‌ها نیاز ندارد استفاده کنید.

بااین‌حال، همان‌طور که در بخش مربوط به onResume ذکر شد، اگر برنامه در حالت چندپنجره‌ای باشد، فعالیت «موقتاً متوقف‌شده» ممکن است همچنان کاملاً قابل‌مشاهده باشد. برای انتشار کامل یا تنظیم منابع و عملیات مربوط به واسط کاربر برای پشتیبانی بهتر از حالت چندپنجره‌ای، بهتر است به‌جای onPause از onStop استفاده کنید.

مثال زیر از LifecycleObserver واکنش نشان دادن به رویداد ON_PAUSE همتای مثال رویداد ON_RESUME قبلی است و دوربینی را که پس‌از دریافت رویداد ON_RESUME مقداردهی اولیه می‌شود آزاد می‌کند:

class CameraComponent : LifecycleObserver {
    ...
    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    fun releaseCamera() {
        camera?.release()
        camera = null
    }
    ...
}

این مثال کد آزاد کردن دوربین را پس‌از دریافت رویداد ON_PAUSE توسط LifecycleObserver قرار می‌دهد.

اجرای onPause بسیار کوتاه است و لزوماً زمان کافی برای انجام عملیات ذخیره ارائه نمی‌دهد. به همین دلیل، از onPause برای ذخیره کردن داده‌های کاربر یا برنامه، برقراری تماس‌های شبکه، یا اجرای تراکنش‌های پایگاه داده استفاده نکنید. چنین کاری ممکن است قبل‌از تکمیل روش تکمیل نشود.

به‌جای آن، عملیات خاموش کردن با بار سنگین را درطول onStop انجام دهید. برای کسب اطلاعات بیشتر درباره عملیات مناسب برای انجام درطول onStop، بخش بعدی را ببینید. برای اطلاعات بیشتر درباره ذخیره کردن داده‌ها، بخش مربوط به ذخیره کردن و بازیابی وضعیت را ببینید.

تکمیل روش onPause به این معنی نیست که فعالیت از حالت «متوقف» خارج می‌شود. بلکه فعالیت تا زمانی که یا ازسر گرفته شود یا برای کاربر کاملاً نامرئی شود در این وضعیت باقی می‌ماند. اگر فعالیت ازسر گرفته شود، سیستم دوباره onResume را فراخوانی می‌کند.

اگر فعالیت از حالت «موقتاً متوقف‌شده» به حالت «ازسرگرفته‌شده» برگردد، سیستم نمونه Activity را در حافظه نگه می‌دارد و وقتی سیستم onResume را فرا می‌خواند، آن نمونه را به‌یاد می‌آورد. در این سناریو، نیازی نیست عناصری را که درطول هریک از روش‌های تماس برگشتی منتهی به حالت «ازسرگرفته‌شده» ایجاد شده‌اند دوباره مقداردهی اولیه کنید. اگر فعالیت کاملاً نامرئی شود، سیستم onStop را فرا می‌خواند.

onStop

وقتی فعالیت شما دیگر برای کاربر قابل‌مشاهده نیست، وارد حالت متوقف‌شده می‌شود و سیستم بازمانی onStop را فرا می‌خواند. این اتفاق زمانی روی می‌دهد که فعالیت جدیدی که راه‌اندازی شده است کل صفحه را بپوشاند. وقتی فعالیت اجرا می‌شود و درحال پایان یافتن است، سیستم onStop را نیز فرا می‌خواند.

وقتی فعالیت به حالت «متوقف» منتقل می‌شود، هر مؤلفه آگاه از چرخه حیات که به چرخه حیات فعالیت مرتبط باشد رویداد ON_STOP را دریافت می‌کند. در اینجا اجزای چرخه حیات می‌توانند هر عملکردی را که نیاز نیست وقتی جزء در صفحه‌نمایش نمایان نیست اجرا شود متوقف کنند.

در روش onStop، منابعی را که درحالی‌که برنامه برای کاربر قابل‌مشاهده نیست لازم نیست آزاد یا تنظیم کنید. برای مثال، برنامه شما ممکن است پویانمایی‌ها را موقتاً متوقف کند یا از به‌روزرسانی‌های مکان دقیق به به‌روزرسانی‌های مکان تقریبی تغییر دهد. استفاده از onStop به‌جای onPause به این معنی است که کار مربوط به رابط کاربری ادامه می‌یابد، حتی زمانی که کاربر فعالیت شما را در حالت چند پنجره‌ای مشاهده می‌کند.

همچنین از onStop برای انجام عملیات خاموش کردن نسبتاً فشرده CPU استفاده کنید. برای مثال، اگر نمی‌توانید زمان بهتری برای ذخیره کردن اطلاعات در پایگاه داده پیدا کنید، ممکن است این کار را درطول onStop انجام دهید. نمونه زیر پیاده‌سازی onStop را نشان می‌دهد که محتوای یادداشت پیش‌نویس را در فضای ذخیره‌سازی ماندگار ذخیره می‌کند:

override fun onStop() {
    super.onStop()

    // Delegate the save operation to the ViewModel, which handles the
    // background thread operations (e.g., using Kotlin Coroutines and Room).
    noteViewModel.saveDraft()
}

وقتی فعالیت شما وارد وضعیت «متوقف» می‌شود، شیء Activity در حافظه مقیم می‌ماند: همه اطلاعات وضعیت و عضو را حفظ می‌کند، اما به مدیر پنجره پیوست نمی‌شود. وقتی فعالیت ازسر گرفته می‌شود، این اطلاعات را به‌یاد می‌آورد.

از حالت «متوقف‌شده»، فعالیت یا برای تعامل با کاربر برمی‌گردد یا اجرای فعالیت تمام می‌شود و ازبین می‌رود. اگر فعالیت برگردد، سیستم onRestart را فرا می‌خواند. اگر Activity اجرای آن تمام شود، سیستم onDestroy را فرا می‌خواند.

onDestroy

‫onDestroy قبل‌از اینکه فعالیت ازبین برود فراخوانی می‌شود. سیستم این بازخوان را به یکی از دو دلیل زیر فرا می‌خواند:

  1. فعالیت درحال اتمام است، زیرا کاربر فعالیت را به‌طور کامل بسته است یا finish در فعالیت فراخوانده شده است.
  2. سیستم به‌دلیل تغییر پیکربندی، مثل چرخش دستگاه یا ورود به حالت چندپنجره‌ای، فعالیت را موقتاً ازبین می‌برد.

وقتی فعالیت به حالت نابودشده منتقل می‌شود، هر مؤلفه آگاه از چرخه حیات مرتبط با چرخه حیات فعالیت، رویداد ON_DESTROY را دریافت می‌کند. در اینجا اجزای چرخه حیات می‌توانند هر چیزی را که نیاز دارند قبل‌از ازبین رفتن Activity پاکسازی کنند.

به‌جای اینکه منطق را در Activity خود قرار دهید تا تعیین کنید چرا ازبین می‌رود، از شیء ViewModel برای نگهداری داده‌های نمای مربوط به Activity خود استفاده کنید. اگر Activity به‌دلیل تغییر پیکربندی بازآفرینی شود، ‫ViewModel لازم نیست کاری انجام دهد، زیرا حفظ می‌شود و به نمونه بعدی Activity داده می‌شود.

اگر Activity بازسازی نشود، ViewModel روش onCleared را فراخوانی می‌کند که در آن می‌تواند هر داده‌ای را که نیاز دارد قبل‌از نابود شدن پاک‌سازی کند. با روش isFinishing می‌توانید این دو سناریو را از هم تشخیص دهید.

اگر فعالیت درحال اتمام است، onDestroy آخرین برگشت‌پذیر چرخه حیات است که فعالیت دریافت می‌کند. اگر onDestroy درنتیجه تغییر پیکربندی فراخوانده شود، سیستم بلافاصله نمونه فعالیت جدیدی ایجاد می‌کند و سپس onCreate را در آن نمونه جدید در پیکربندی جدید فرا می‌خواند.

کاربرگشتی onDestroy همه منابعی را که کاربرگشتی‌های قبلی آزاد نکرده‌اند، مثل onStop، آزاد می‌کند.

وضعیت فعالیت و بیرون کردن از حافظه

وقتی سیستم نیاز به آزاد کردن RAM داشته باشد، فرایندها را می‌بندد. احتمال اینکه سیستم یک فرایند معین را متوقف کند به وضعیت فرایند در آن زمان بستگی دارد. وضعیت فرایند به نوبه خود به وضعیت فعالیت درحال اجرا در فرایند بستگی دارد. جدول ۱ همبستگی بین وضعیت پردازش، وضعیت فعالیت، و احتمال اینکه سیستم پردازش را متوقف کند را نشان می‌دهد. این جدول فقط درصورتی اعمال می‌شود که فرایندی انواع دیگر عناصر برنامه را اجرا نکند.

احتمال کشته شدن

وضعیت پردازش

وضعیت نهایی فعالیت

پایین‌ترین

پیش‌زمینه (دارای تمرکز یا درحال دریافت تمرکز)

ازسرگرفت

کم

رؤیت‌پذیر (بدون تمرکز)

شروع شد/موقتاً متوقف شد

بالاتر

پس‌زمینه (نامرئی)

متوقف‌شده

بالاترین

خالی

ازبین‌رفته

جدول ۱. رابطه بین چرخه حیات فرایند و وضعیت فعالیت.

سیستم هرگز فعالیت را مستقیماً برای آزاد کردن حافظه نمی‌کشد. درعوض، فرایندی را که فعالیت در آن اجرا می‌شود می‌کشد و نه تنها فعالیت بلکه هر چیز دیگری را که در فرایند اجرا می‌شود نیز ازبین می‌برد. برای آشنایی با نحوه حفظ و بازیابی وضعیت واسط کاربر فعالیتتان هنگام وقوع مرگ فرایند آغازشده توسط سیستم، به بخش مربوط به ذخیره و بازیابی وضعیت مراجعه کنید.

کاربر همچنین می‌تواند بااستفاده از «مدیر برنامه» در بخش «تنظیمات»، برنامه مربوطه را متوقف کند و از این طریق فرایند را متوقف کند.

برای اطلاعات بیشتر درباره فرایندها، مروری بر فرایندها و رشته‌ها را ببینید.

درحال ذخیره و بازیابی وضعیت واسط کاربر گذرا

کاربر انتظار دارد وضعیت میانای کاربر فعالیت درطول تغییر پیکربندی، مثل چرخش یا رفتن به حالت چندپنجره‌ای، یکسان باقی بماند. بااین‌حال، وقتی چنین پیکربندی‌ای تغییر می‌کند، سیستم به‌طور پیش‌فرض فعالیت را ازبین می‌برد و هر وضعیت رابط کاربری ذخیره‌شده در نمونه فعالیت را پاک می‌کند.

به‌همین ترتیب، کاربر انتظار دارد وضعیت «میانای کاربر» یکسان باقی بماند اگر به‌طور موقت از برنامه شما به برنامه دیگری برود و سپس به برنامه شما برگردد. بااین‌حال، سیستم می‌تواند فرایند برنامه شما را درحالی‌که کاربر دور است و فعالیت شما متوقف شده است ازبین ببرد.

وقتی محدودیت‌های سیستم فعالیت را ازبین می‌برد، وضعیت میانای کاربر گذرا را بااستفاده از ترکیبی از ViewModel (برای منطق کسب‌وکار پیچیده و وضعیت صفحه)، Jetpack Compose rememberSaveable API (برای وضعیت میانای کاربر سبک)، و/یا فضای ذخیره‌سازی محلی حفظ کنید. برای کسب اطلاعات بیشتر درباره انتظارات کاربر در مقایسه با عملکرد سیستم و نحوه حفظ بهتر داده‌های وضعیت رابط کاربری پیچیده در فعالیت‌های آغازشده توسط سیستم و مرگ فرایند، به ذخیره وضعیت‌های رابط کاربری مراجعه کنید.

‫rememberSaveable با دسته‌بندی وضعیت در زیر پوسته، به‌طور خودکار از تغییرات پیکربندی و مرگ فرایند آغازشده توسط سیستم جان سالم به‌در می‌برد و تجربه‌ای یکپارچه بدون نیاز به کد قالبی سطح فعالیت ارائه می‌دهد.

وضعیت نمونه

چند سناریو وجود دارد که در آن‌ها فعالیت شما به‌دلیل عملکرد عادی برنامه ازبین می‌رود، مثلاً زمانی که کاربر دکمه «برگشتن» را فشار می‌دهد یا فعالیت شما با فراخوانی روش finish ازبین رفتن خود را اعلام می‌کند.

وقتی فعالیت شما به‌دلیل فشار دادن «بازگشت» توسط کاربر یا به‌دلیل اینکه فعالیت خودبه‌خود تمام می‌شود ازبین می‌رود، هم مفهوم سیستم و هم مفهوم کاربر از آن نمونه Activity برای همیشه ازبین می‌رود. در این سناریوها، انتظار کاربر با عملکرد سیستم مطابقت دارد و شما کار اضافه‌ای برای انجام دادن ندارید.

بااین‌حال، اگر سیستم فعالیت را به‌دلیل محدودیت‌های سیستم (مثل تغییر پیکربندی یا فشار حافظه) ازبین ببرد، اگرچه نمونه Activity واقعی ازبین می‌رود، سیستم به‌یاد می‌آورد که وجود داشته است. اگر کاربر تلاش کند به فعالیت برگردد، سیستم نمونه جدیدی از آن فعالیت را بااستفاده از مجموعه‌ای از داده‌های ذخیره‌شده که وضعیت فعالیت را هنگام ازبین رفتن آن توصیف می‌کند ایجاد می‌کند.

داده‌های ذخیره‌شده‌ای که سیستم برای بازیابی حالت قبلی استفاده می‌کند حالت نمونه نامیده می‌شود. در زیر، مجموعه‌ای از جفت‌های کلید-مقدار است. به‌طور پیش‌فرض، سیستم از وضعیت نمونه برای ذخیره کردن اطلاعات پایه درباره چیدمان واسط کاربر شما، مثل ورودی نوشتاری کاربر یا موقعیت‌های پیمایش، استفاده می‌کند.

بااستفاده از rememberSaveable، به این رفتار سیستم متصل می‌شوید. اگر نمونه فعالیت شما ازبین برود و دوباره ایجاد شود، هر وضعیت رابط کاربری که در rememberSaveable پیچیده شده باشد به‌طور خودکار بازیابی می‌شود و هیچ کد سطح فعالیت اضافی‌ای ازطرف شما لازم نیست.

بااین‌حال، فعالیت شما احتمالاً اطلاعات وضعیت پیچیده‌تری دارد که می‌خواهید بازیابی کنید، مثل داده‌های کاربر، پاسخ‌های شبکه، یا متغیرهای عضو که پیشرفت کاربر را پیگیری می‌کنند. سازوکار وضعیت نمونه (و به‌تبع آن، rememberSaveable) برای حفظ بیش‌از مقدار ناچیزی از داده‌ها مناسب نیست، زیرا به سریال‌سازی در رشته اصلی نیاز دارد و حافظه فرایند سیستم را مصرف می‌کند.

برای حفظ کردن بیش از مقدار بسیار کمی از داده‌ها، از رویکرد ترکیبی بااستفاده از فضای ذخیره‌سازی محلی ماندگار، کلاس ViewModel، و بالابردن وضعیت Compose، همان‌طور که در ذخیره وضعیت‌های واسط کاربر توضیح داده شده است، استفاده کنید.

ذخیره حالت میانای کاربر ساده و سبک بااستفاده از rememberSaveable

وقتی فعالیت شما متوقف می‌شود، سیستم آماده می‌شود تا اطلاعات وضعیت را در بسته وضعیت نمونه ذخیره کند. برای اتصال به این رفتار سیستم، از rememberSaveable مستقیماً در توابع ترکیب‌پذیر استفاده می‌کنید. ‫rememberSaveable به‌طور خودکار وضعیت میانای کاربر گذرا، مثل ورودی نوشتاری کاربر یا موقعیت‌های پیمایش، را در سراسر بازآفرینی فعالیت ذخیره و بازیابی می‌کند.

برای ذخیره کردن اطلاعات وضعیت سفارشی و سبک (مثل پیشرفت کاربر در یک بازی)، وضعیتتان را بااستفاده از rememberSaveable اعلام کنید. چارچوب Compose سریال‌سازی را در بسته وضعیت نمونه در پشت صحنه مدیریت می‌کند:

var userTypedQuery by rememberSaveable(typedQuery, stateSaver = TextFieldValue.Saver) {
    mutableStateOf(
        TextFieldValue(text = typedQuery, selection = TextRange(typedQuery.length))
    )
}

برای ذخیره کردن داده‌های ماندگار، مثل اولویت‌های کاربر یا داده‌های پایگاه داده، وقتی فعالیتتان در پیش‌زمینه است از فرصت‌های مناسب استفاده کنید. اگر چنین فرصتی پیش نیامد، داده‌های ماندگار را درطول روش onStop ذخیره کنید.

بازگرداندن وضعیت واسط کاربر فعالیت بااستفاده از وضعیت نمونه ذخیره‌شده

وقتی فعالیت شما پس‌از اینکه قبلاً ازبین رفته است بازسازی می‌شود، بازیابی وضعیت به‌طور خودکار انجام می‌شود. وقتی از rememberSaveable استفاده می‌کنید، نیازی نیست منطق بازیابی صریحی بنویسید، دسته‌های تهی را بررسی کنید، یا بازخوان‌های فعالیت را ملغی کنید. کدی که وضعیت شما را مقداردهی اولیه و ذخیره می‌کند، وقتی فعالیت برمی‌گردد آن را به‌طور یکپارچه بازیابی می‌کند:

var userTypedQuery by rememberSaveable(typedQuery, stateSaver = TextFieldValue.Saver) {
    mutableStateOf(
        TextFieldValue(text = typedQuery, selection = TextRange(typedQuery.length))
    )
}

فعالیت‌ها و پیمایش

برنامه احتمالاً در طول عمر خود بارها بین صفحه‌ها جابه‌جا می‌شود، مثلاً وقتی کاربر روی دکمه «بازگشت» دستگاه ضربه می‌زند یا مقصد جدیدی را انتخاب می‌کند. برنامه‌های مدرن Android معمولاً از معماری تک‌فعالیتی استفاده می‌کنند. به‌جای اینکه برای هر صفحه Activity جدیدی شروع کنید، برنامه شما Activity واحدی را میزبانی می‌کند و از عنصر Navigation برای تعویض صفحه‌های ترکیب‌پذیر در آن فعالیت استفاده می‌کند.

برای آشنایی با نحوه پیاده‌سازی ناوبری مدرن و Compose-first، راهنمای کتابخانه Navigation 3 در Jetpack Compose را ببینید.

شروع یک فعالیت از فعالیتی دیگر

فعالیت ممکن است در نقطه‌ای نیاز داشته باشد فعالیت دیگری را شروع کند. این نیاز برای مثال زمانی پیش می‌آید که برنامه‌ای نیاز دارد از صفحه فعلی به صفحه جدیدی منتقل شود.

بسته به اینکه فعالیت شما بخواهد از فعالیت جدیدی که قرار است شروع شود نتیجه‌ای دریافت کند یا نه، فعالیت جدید را بااستفاده از روش startActivity یا روش startActivityForResult شروع می‌کنید. در هر دو حالت، یک شیء Intent را ارسال می‌کنید.

شیء Intent یا فعالیت دقیقی را که می‌خواهید شروع کنید مشخص می‌کند یا نوع کنشی را که می‌خواهید انجام دهید توصیف می‌کند. سیستم فعالیت مناسب را برای شما انتخاب می‌کند، که حتی می‌تواند از برنامه دیگری باشد. یک Intent شیء می‌تواند مقادیر کمی از داده‌ها را نیز برای استفاده توسط فعالیت شروع‌شده حمل کند. برای اطلاعات بیشتر درباره کلاس Intent، هدف‌ها و فیلترهای هدف را ببینید.

شروع فعالیت

اگر فعالیت جدیداً شروع‌شده نیازی به برگرداندن نتیجه نداشته باشد، فعالیت فعلی می‌تواند آن را با فراخوانی روش startActivity شروع کند.

هنگام کار در برنامه خودتان، اغلب باید به‌سادگی یک فعالیت شناخته‌شده را راه‌اندازی کنید. برای مثال، تکه‌کد زیر نحوه راه‌اندازی یک فعالیت به‌نام SignInActivity را نشان می‌دهد.

val context = LocalContext.current

Button(onClick = {
    val intent = Intent(context, SignInActivity::class.java)
    context.startActivity(intent)
}) {
    Text("Sign In")
}

شروع فعالیت‌های خارجی

درحالی‌که ناوبری برنامه داخلی توسط Navigation مدیریت می‌شود، Activity شما گاهی اوقات باید فعالیت‌های دیگر را شروع کند. این اتفاق معمولاً زمانی رخ می‌دهد که بخواهید از یک برنامه خارجی برای انجام کنش خاصی، مثل باز کردن مرورگر وب، ارسال ایمیل، یا گرفتن عکس استفاده کنید.

برای دستیابی به این هدف، از شیء Intent برای توصیف نوع کنشی که می‌خواهید انجام دهید استفاده می‌کنید و سیستم فعالیت مناسب را از برنامه دیگری راه‌اندازی می‌کند.

برای مثال، اگر می‌خواهید به کاربر اجازه دهید پیام ایمیل ارسال کند، می‌توانید قصد زیر را ایجاد کنید:

val intent = Intent(Intent.ACTION_SEND).apply {
    putExtra(Intent.EXTRA_EMAIL, recipientArray)
}
startActivity(intent)

اگر نیاز دارید فعالیت خارجی راه‌اندازی کنید و نتیجه‌ای دریافت کنید (مثلاً از برنامه دوربین بخواهید عکس بگیرد و تصویر را برگرداند)، به‌جای startActivityForResult تماس برگشتی منسوخ‌شده، از Activity میاناهای برنامه‌سازی کاربردی نتیجه مدرن استفاده کنید.

هماهنگی فعالیت‌ها

وقتی یک فعالیت فعالیت دیگری را شروع می‌کند، هر دو فعالیت گذرهای چرخه حیات را تجربه می‌کنند. فعالیت اول از کار می‌افتد و وارد وضعیت «موقتاً متوقف» یا «متوقف» می‌شود، درحالی‌که فعالیت دیگر ایجاد می‌شود. درصورتی‌که این فعالیت‌ها از داده‌های ذخیره‌شده در دیسک یا جای دیگر استفاده کنند، مهم است بدانید که فعالیت اول قبل‌از ایجاد فعالیت دوم به‌طور کامل متوقف نمی‌شود. بلکه فرایند شروع دومی با فرایند توقف اولی هم‌پوشانی دارد.

ترتیب فراخوان‌های برگشتی چرخه حیات به‌خوبی تعریف شده است، به‌ویژه زمانی که دو فعالیت در یک فرایند—به‌عبارت دیگر، یک برنامه—قرار دارند و یکی دیگری را شروع می‌کند. ترتیب عملیاتی که هنگام شروع «فعالیت B» توسط «فعالیت A» رخ می‌دهد به این صورت است:

  1. روش onPause فعالیت A اجرا می‌شود.
  2. روش‌های onCreate، onStart، و onResume فعالیت B به‌ترتیب اجرا می‌شوند. اکنون فعالیت B تمرکز کاربر را دارد.
  3. اگر «فعالیت A» دیگر در صفحه رؤیت‌پذیر نباشد، روش onStop آن اجرا می‌شود.

این توالی از توابع برگشتی چرخه حیات به شما امکان می‌دهد انتقال اطلاعات از یک فعالیت به فعالیت دیگر را مدیریت کنید.

منابع بیشتر

برای کسب اطلاعات بیشتر درباره چرخه حیات فعالیت، به منابع تکمیلی زیر مراجعه کنید:

محتوا را می‌بیند