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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

نوشتن و چرخه حیات

در Compose، از قرار دادن منطق تجاری یا تنظیم دستی ناظر (Observer Setup) مستقیماً در فراخوانی‌های فعالیت مانند onStart یا onResume خودداری کنید. در عوض، از جلوه‌های Lifecycle -aware و ناظرهای state-aware استفاده کنید که به طور خودکار با حضور UI روی صفحه هماهنگ می‌شوند.

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

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

فراخوانی‌های چرخه عمر

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

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

روی ایجاد

شما باید این تابع فراخوانی (callback) را پیاده‌سازی کنید، که وقتی سیستم برای اولین بار activity را ایجاد می‌کند، اجرا می‌شود. در هنگام ایجاد activity، activity وارد حالت Created می‌شود. در متد onCreate ، منطق اولیه راه‌اندازی برنامه را که فقط یک بار در کل طول عمر activity اتفاق می‌افتد، اجرا کنید.

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

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

مثال زیر نحوه ادغام یک Text composable را در یک activity ساده نشان می‌دهد:

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!")
}

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

شروع

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

وقتی اکتیویتی به حالت شروع‌شده (Started) می‌رود، هر کامپوننت آگاه از چرخه حیات (lifecycle-aware) که به چرخه حیات اکتیویتی گره خورده است، رویداد ON_START دریافت می‌کند.

متد onStart به سرعت تکمیل می‌شود و مانند حالت Created، اکتیویتی در حالت Started باقی نمی‌ماند. پس از پایان این فراخوانی، اکتیویتی وارد حالت Resume می‌شود و سیستم متد onResume فراخوانی می‌کند.

در رزومه

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

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

وقتی یک رویداد وقفه‌دار رخ می‌دهد، فعالیت وارد حالت Paused می‌شود و سیستم فراخوانی onPause را فراخوانی می‌کند.

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

در اینجا مثالی از یک کامپوننت آگاه از چرخه حیات (lifecycle-aware) آورده شده است که وقتی کامپوننت رویداد ON_RESUME دریافت می‌کند، به دوربین دسترسی پیدا می‌کند:

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

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

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

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

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

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

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

onPause

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

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

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

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

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

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

مثال زیر از یک 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 به این معنی نیست که اکتیویتی از حالت Paused خارج می‌شود. بلکه، اکتیویتی در این حالت باقی می‌ماند تا زمانی که یا اکتیویتی از سر گرفته شود یا کاملاً برای کاربر نامرئی شود. اگر اکتیویتی از سر گرفته شود، سیستم بار دیگر فراخوانی onResume را فراخوانی می‌کند.

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

آن‌استاپ

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

وقتی اکتیویتی به حالت متوقف‌شده (Stopped) می‌رود، هر کامپوننت آگاه از چرخه حیات که به چرخه حیات اکتیویتی گره خورده است، رویداد 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 قبل از اینکه اکتیویتی از بین برود، فراخوانی می‌شود. سیستم این فراخوانی را به یکی از دو دلیل زیر فراخوانی می‌کند:

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

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

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

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

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

تابع فراخوانی onDestroy تمام منابعی را که توسط توابع فراخوانی قبلی مانند onStop آزاد نشده‌اند، آزاد می‌کند.

وضعیت فعالیت و حذف از حافظه

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

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

وضعیت فرآیند

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

کمترین

پیش‌زمینه (داشتن یا در شرف گرفتن فوکوس)

از سر گرفته شد

کم

قابل مشاهده (بدون فوکوس)

شروع/مکث

بالاتر

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

متوقف شد

بالاترین

خالی

ویران شده

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

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

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

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

ذخیره و بازیابی حالت گذرای رابط کاربری

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

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

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

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

حالت نمونه

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

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

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

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

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

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

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

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

همزمان با شروع توقف فعالیت شما، سیستم آماده ذخیره اطلاعات وضعیت در یک بسته وضعیت نمونه می‌شود. برای اتصال به این رفتار سیستم، می‌توانید rememberSaveable مستقیماً در توابع composable خود استفاده کنید. 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))
    )
}

فعالیت‌ها و ناوبری

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

برای یادگیری نحوه پیاده‌سازی ناوبری مدرن و مبتنی بر Compose، به راهنمای کتابخانه Jetpack Compose Navigation 3 مراجعه کنید.

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

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

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

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

شروع فعالیت

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

هنگام کار در برنامه خودتان، اغلب نیاز دارید که به سادگی یک activity شناخته شده را راه اندازی کنید. برای مثال، قطعه کد زیر نحوه راه اندازی activity ای به نام 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 خارجی را اجرا کنید و نتیجه‌ای را دریافت کنید (مانند درخواست از برنامه دوربین برای گرفتن عکس و بازگرداندن تصویر)، از APIهای مدرن Activity result به جای callback منسوخ‌شده startActivityForResult استفاده کنید.

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

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

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

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

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

منابع اضافی

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

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