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

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

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

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

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

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

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

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

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

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

شکل ۱ نمایش دیداری این الگو را نشان می‌دهد.

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

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

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

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

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

Compose و چرخه حیات

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

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

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

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

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

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

onCreate

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

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

اگر مؤلفه آگاه از چرخه حیات دارید که به چرخه حیات فعالیتتان متصل است، رویداد 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 مقداردهی اولیه کنید.

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

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

Regardless of which build-up event you choose to perform an initialization operation in, make sure to use the corresponding lifecycle event to release the resource. اگر چیزی را بعداز رویداد 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 را فراخوانی می‌کند، آن نمونه را فراخوانی می‌کند. در این سناریو، نیازی به مقداردهی اولیه مجدد مؤلفه‌های ایجادشده درطول هیچ‌یک از روش‌های callback که به حالت «ازسرگرفته‌شده» منتهی می‌شوند ندارید. اگر فعالیت کاملاً نامرئی شود، سیستم onStop را فراخوانی می‌کند.

onStop

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

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

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

همچنین، از 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

اگر فعالیت جدیداً شروع‌شده نیازی به برگرداندن نتیجه نداشته باشد، فعالیت فعلی می‌تواند آن را با فراخوانی روش 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)

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

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

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

ترتیب فراخوانی‌های چرخه حیات به‌خوبی تعریف شده است، به‌ویژه زمانی که دو فعالیت در یک فرایند باشند (به‌عبارت دیگر، در یک برنامه باشند) و یکی دیگری را شروع کند. در اینجا ترتیب عملیاتی که هنگام شروع «فعالیت ب» توسط «فعالیت الف» رخ می‌دهد آورده شده است:

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

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

منابع بیشتر

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

محتوا را مشاهده می‌کند