LifecycleOwner — یک رابط کلیدی از کتابخانه Android Jetpack است که اعلام میکند یک شیء دارای چرخه حیات است و از طریق متد getLifecycle() به آن دسترسی فراهم میکند. این رابط در پایه معماری کامپوننتی برنامههای مدرن اندروید قرار دارد و اجازه میدهد منطق کار با چرخه حیات از پیادهسازی مشخص Activity یا Fragment جدا شود. طبق دادههای Google I/O 2024، بیش از 85٪ پروژههای جدید در اندروید از LifecycleOwner برای مدیریت اشتراکها و جلوگیری از نشت حافظه استفاده میکنند. این رابط پایهای برای LiveData، ViewModel و سایر کامپوننتهای Jetpack است و اجرای ایمن کد را فقط در حالت فعال کامپوننت تضمین میکند.
نکات اصلی
LifecycleOwner — یک رابط از بسته androidx.lifecycle است که حاوی یک متد واحد getLifecycle() است که شیء Lifecycle را برمیگرداند. این شیء وضعیت فعلی کامپوننت (CREATED, STARTED, RESUMED, DESTROYED) را追踪 میکند و در هنگام تغییر آن همه مشاهدهگرهای مشترک را مطلع میکند. LifecycleOwner بخشی از Architecture Components است و در کتابخانه lifecycle-runtime قرار دارد.
وظیفه اصلی رابط — استانداردسازی دسترسی به چرخه حیات است. قبل از ظهور Jetpack، توسعهدهندگان از اشتراک دستی در onStart و لغو اشتراک در onStop استفاده میکردند که منجر به تکرار کد و خطاها میشد. LifecycleOwner این مشکل را با ارائه یک مکانیسم واحد برای تمام کامپوننتهای اندروید حل میکند. به جای فراخوانی صریح متدهای چرخه حیات، توسعهدهنده یک بار در Lifecycle مشترک میشود و اعلانها به طور خودکار میرسند.
این رابط در Kotlin به عنوان یک رابط تابعی با یک متد انتزاعی اعلام شده است:
interface LifecycleOwner {
val lifecycle: Lifecycle
}
به دلیل ماهیت تابعی رابط، پیادهسازی آن با استفاده از delegate یا لامبدا آسان است. این به ویژه برای ایجاد Custom Views و کلاسهای ViewModel که باید به تغییرات چرخه حیات میزبان واکنش نشان دهند، مناسب است. شیء Lifecycle به دست آمده از getLifecycle() متدهای addObserver و removeObserver را برای مدیریت اشتراکها فراهم میکند.
LifecycleOwner در ترکیب با دو کلاس کلیدی کار میکند: Lifecycle و LifecycleObserver. Lifecycle وضعیت فعلی کامپوننت را به صورت enum State (INITIALIZED, CREATED, STARTED, RESUMED, DESTROYED) ذخیره میکند و انتقال بین آنها را追踪 میکند. هنگامی که وضعیت تغییر میکند، Lifecycle همه مشاهدهگرهای ثبتشده را مطلع میکند و متدهای حاشیهنویسی شده مربوطه را فراخوانی میکند. این مکانیسم "lifecycle-aware" نامیده میشود — کد فقط زمانی اجرا میشود که کامپوننت در وضعیت مناسب باشد.
مکانیسم انتقال رویدادها بر اساس الگوی Observer است. LifecycleOwner نقش Observable را ایفا میکند و پیادهسازی LifecycleObserver نقش Observer را. Activity یا Fragment هنگام تغییر وضعیت خود (onCreate → onStart → onResume → onPause → onStop → onDestroy) از طریق مکانیسم داخلی ReportFragment که به طور خودکار به سیستم AndroidX اضافه میشود، Lifecycle را مطلع میکند. توسعهدهنده نیازی به فراخوانی دستی متدهای Lifecycle ندارد — همه چیز به طور خودکار انجام میشود.
| وضعیت Lifecycle | رویداد | متد چرخه حیات اندروید |
|---|---|---|
| INITIALIZED | — | قبل از onCreate |
| CREATED | ON_CREATE | onCreate |
| STARTED | ON_START | onStart |
| RESUMED | ON_RESUME | onResume |
| STARTED | ON_PAUSE | onPause |
| CREATED | ON_STOP | onStop |
| DESTROYED | ON_DESTROY | onDestroy |
جزئیات مهم: Lifecycle تضمین میکند که رویدادهای ON_STOP و ON_DESTROY حتی در صورت خاتمه اضطراری فرآیند تحویل داده میشوند. این LifecycleOwner را به ابزاری قابل اعتماد برای آزادسازی منابع بحرانی تبدیل میکند. برای ذخیرهسازی معمولی وضعیت، توصیه میشود از SavedStateHandle در ViewModel استفاده کنید، اما LifecycleOwner سطح پایهای امنیت را فراهم میکند.
دو روش برای اشتراک رویدادهای LifecycleOwner وجود دارد: کلاسیک LifecycleObserver با حاشیهنویسی و مدرن DefaultLifecycleObserver با متدهای صریح. رویکرد دوم از سال 2022 توسط Google توصیه میشود، زیرا امنیت نوع بهتری ارائه میدهد و از بازتاب (reflection) که در رویکرد حاشیهنویسی استفاده میشد، اجتناب میکند. DefaultLifecycleObserver نیاز به Java 8+ یا Kotlin دارد و برای پروژههای جدید ترجیح داده میشود.
مثال اشتراک از طریق DefaultLifecycleObserver:
class MyObserver : DefaultLifecycleObserver {
override fun onStart(owner: LifecycleOwner) {
// راهاندازی ردیابی GPS فقط زمانی که کامپوننت فعال است
startLocationUpdates()
}
override fun onStop(owner: LifecycleOwner) {
// توقف ایمن هنگام انتقال به حالت پسزمینه
stopLocationUpdates()
}
}
// اتصال:
lifecycleOwner.lifecycle.addObserver(MyObserver())
هر متد DefaultLifecycleObserver LifecycleOwner را به عنوان پارامتر دریافت میکند. این به مشاهدهگر اجازه میدهد بدون نیاز به ارسال جداگانه به زمینه کامپوننت در حال اجرا دسترسی پیدا کند. این رویکرد کد را ماژولارتر و قابل آزمایشتر میکند — Observer به پیادهسازی مشخص Activity یا Fragment وابسته نیست، بلکه با انتزاع LifecycleOwner کار میکند.
روش قدیمی با استفاده از حاشیهنویسی @OnLifecycleEvent هنوز در پروژههای legacy دیده میشود، اما استفاده از آن برای کد جدید توصیه نمیشود. بازتاب مورد نیاز برای پردازش حاشیهنویسیها سربار اضافه میکند و میتواند منجر به خطاهایی شود که در مرحله کامپایل شناسایی نمیشوند. Google به طور رسمی مهاجرت به DefaultLifecycleObserver را توصیه میکند.
// رویکرد قدیمی — برای پروژههای جدید توصیه نمیشود
class MyLegacyObserver : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onStart() {
startLocationUpdates()
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onStop() {
stopLocationUpdates()
}
}
رویکرد حاشیهنویسی یک نقص اساسی دارد: عدم کنترل طول عمر Observer. اگر توسعهدهنده فراموش کند Observer را هنگام نابودی LifecycleOwner لغو اشتراک کند، شیء Observer تا زمانی که جمعآوری زباله اجرا شود در حافظه باقی میماند. DefaultLifecycleObserver این مشکل را حل میکند — Observer به Lifecycle متصل است و هنگام انتقال به وضعیت DESTROYED به طور خودکار لغو اشتراک میشود.
از AppCompat 1.1.0 و AndroidX Fragment 1.2.0 به بعد، تمام Activity و Fragment که از AppCompatActivity یا Fragment ارث میبرند به طور خودکار LifecycleOwner هستند. این بدان معناست که متد getLifecycle() به طور پیشفرض در آنها در دسترس است و اشتراک رویدادهای چرخه حیات بدون پیکربندی اضافی کار میکند. توسعهدهنده فقط باید lifecycle.addObserver() را از هر جایی در Activity یا Fragment فراخوانی کند.
مثال ادغام LifecycleOwner در Activity:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycle.addObserver(LocationObserver(this))
}
}
در این مثال lifecycle یک extension property است که به لطف AndroidX Activity در دسترس است. Observer LocationObserver به طور خودکار اعلانهایی درباره شروع (ON_START) و توقف (ON_STOP) Activity دریافت میکند. هنگام چرخش صفحه، Observer از ON_DESTROY و سپس ON_CREATE مطلع میشود که به پردازش صحیح تغییرات پیکربندی بدون کد اضافی کمک میکند.
Fragment LifecycleOwner را از طریق رابط پیادهسازی میکند و Lifecycle آن به چرخه حیات Fragment متصل است، نه Activity والد. این مهم است: Lifecycle Fragment وقتی Fragment از تراکنش حذف میشود به DESTROYED میرود، در حالی که Activity ممکن است در RESUMED باقی بماند. این تفاوت به Observer اجازه میدهد به طور جداگانه در چرخه حیات هر کامپوننت مشترک شود.
class MyFragment : Fragment() {
private val uiStateObserver = UiStateObserver()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
lifecycle.addObserver(uiStateObserver)
}
}
مزیت مهم استفاده از LifecycleOwner در Fragment — لغو اشتراک خودکار هنگام انتقال Fragment به DESTROYED. این به ویژه برای ViewPager که در آن Fragmentها ممکن است به صورت پویا ایجاد و نابود شوند، مرتبط است. مدیریت دستی اشتراکها در این سناریو بسیار پیچیده و مستعد خطا بود.
رابط LifecycleOwner را میتوان در هر کلاسی که چرخه حیات دارد پیادهسازی کرد. این برای Custom Views، Service و حتی ViewModel در برخی راهحلهای معماری مفید است. Google کلاس کمکی LifecycleRegistry را ارائه میدهد که وضعیت Lifecycle را مدیریت میکند و رویدادها را تولید میکند. توسعهدهنده باید هنگام تغییر وضعیت کامپوننت، متدهای مربوطه LifecycleRegistry را به صورت دستی فراخوانی کند.
مثال پیادهسازی LifecycleOwner در Custom View:
class MyCustomView(
context: Context,
attrs: AttributeSet?
) : FrameLayout(context, attrs), LifecycleOwner {
private val lifecycleRegistry = LifecycleRegistry(this)
override val lifecycle: Lifecycle
get() = lifecycleRegistry
fun onStart() {
lifecycleRegistry.setCurrentState(Lifecycle.State.STARTED)
}
fun onStop() {
lifecycleRegistry.setCurrentState(Lifecycle.State.CREATED)
}
}
در این مثال LifecycleRegistry به عنوان ذخیرهساز وضعیت عمل میکند. متدهای onStart/onStop باید توسط کامپوننت والد (مثلاً Activity) هنگامی که Custom View قابل مشاهده یا پنهان میشود فراخوانی شوند. LifecycleRegistry به طور خودکار رویدادهای لازم برای انتقال بین وضعیتها را محاسبه میکند و همه Observerهای مشترک را مطلع میکند.
در پیادهسازی LifecycleOwner سفارشی، رعایت این قانون مهم است: وضعیت LifecycleRegistry باید در متد مربوطه چرخه حیات، پس از همه عملیاتهای دیگر، آخرین بهروزرسانی شود. این تضمین میکند که Observerها زمانی که کامپوننت کاملاً برای وضعیت جدید آماده است، اعلان دریافت کنند. استفاده از LifecycleRegistry.createUnsafe به عنوان جایگزین نیز ممکن است، اما نیاز به احتیاط با نخها دارد.
LifecycleOwner پایهای برای چندین کامپوننت کلیدی Android Jetpack است. LiveData از LifecycleOwner برای تعیین وضعیت فعال و لغو اشتراک خودکار هنگام نابودی کامپوننت استفاده میکند. ViewModel مستقیماً LifecycleOwner را پیادهسازی نمیکند، اما میتواند از طریق SavedStateHandle Lifecycle دریافت کند. Navigation Component از LifecycleOwner برای مدیریت اشتراکها در NavBackStackEntry استفاده میکند. درک این ارتباط به ساخت معماری برنامه بر پایهای محکم کمک میکند.
تعامل LiveData با LifecycleOwner:
class ExampleActivity : AppCompatActivity() {
private val viewModel: ExampleViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel.userData.observe(this) { data ->
// this — LifecycleOwner (Activity)
// کد فقط زمانی اجرا میشود که Activity در وضعیت RESUMED است
updateUI(data)
}
}
}
LiveData در متد observe() به LifecycleOwner نیاز دارد، زیرا این تضمین میکند که بهروزرسانیهای UI فقط در وضعیت فعال رخ میدهند. اگر Activity در پسزمینه باشد، LiveData آخرین مقدار را حفظ میکند اما Observer را مطلع نمیکند. هنگام بازگشت به RESUMED، Observer بدون درخواست اضافی به شبکه یا پایگاه داده، مقدار فعلی را دریافت میکند.
DataBinding نیز از LifecycleOwner برای اتصال فیلدهای observable به چرخه حیات Activity یا Fragment استفاده میکند. این از نشت حافظه در ترکیب ViewModel + DataBinding جلوگیری میکند — همه اشتراکها هنگام نابودی LifecycleOwner به طور خودکار پاک میشوند. این رویکرد کد را اعلانی و ایمن میکند.
استفاده صحیح از LifecycleOwner نیاز به رعایت چند قانون کلیدی دارد. اولین و مهمترین: همیشه Observer را در onCreate/onViewCreated مشترک کنید، نه دیرتر. این تضمین میکند که Observer وضعیت اولیه Lifecycle (CREATED پس از onCreate) را دریافت میکند و رویدادها را از دست نمیدهد. قانون دوم: از DefaultLifecycleObserver به جای رویکرد حاشیهنویسی برای همه پروژههای جدید استفاده کنید.
رویکرد مدرن برای کار با کروتینها و LifecycleOwner — افزونه repeatOnLifecycle:
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.flow.collect { value ->
updateUI(value)
}
}
}
این الگو تضمین میکند که collect روی Flow فقط در وضعیت STARTED یا RESUMED فعال است. هنگام انتقال به STOPPED، جمعآوری به طور خودکار لغو میشود و هنگام بازگشت به STARTED، دوباره راهاندازی میشود. repeatOnLifecycle جایگزین لغو اشتراک دستی از Flow در Fragment میشود و رویکرد توصیهشده Google برای کار با جریانهای داده ناهمزمان در کامپوننتهای UI است.
یک توصیه مهم دیگر: از LifecycleObserver برای منطق غیرمرتبط با چرخه حیات سوءاستفاده نکنید. اگر کامپوننت باید در وضعیت خاصی عملی انجام دهد اما هنگام نابودی نیاز به لغو اشتراک ندارد، بهتر است از فراخوانی صریح متدها در onStart/onStop استفاده کنید. LifecycleObserver برای کامپوننتهای طولانیمدت (LocationListener, SensorManager) توجیهپذیر است، جایی که مدیریت دستی اشتراکها پیچیده و مستعد خطا است.
سوالات متداول
LifecycleOwner — یک رابط است که اعلام میکند یک شیء چرخه حیات دارد. Lifecycle — کلاسی است که وضعیت فعلی را ذخیره میکند و Observer را مدیریت میکند. LifecycleOwner از طریق getLifecycle() Lifecycle را فراهم میکند.
خیر، Lifecycle هنگام انتقال به DESTROYED به طور خودکار همه Observerها را لغو اشتراک میکند. این یکی از مزایای اصلی LifecycleOwner است — توسعهدهنده نیازی به فراخوانی دستی removeObserver در onDestroy ندارد.
Fragment LifecycleOwner را از طریق رابط فرگمنتهای AndroidX پیادهسازی میکند. Lifecycle آن به چرخه حیات Fragment به طور جداگانه از Activity متصل است. این به Observer اجازه میدهد به رویدادهای Fragment واکنش نشان دهد، نه Activity والد.
بله، برای این کار از LifecycleRegistry استفاده میشود. Custom View باید رابط LifecycleOwner را پیادهسازی کند و به صورت دستی وضعیت LifecycleRegistry را هنگام تغییر دید یا اتصال به پنجره بهروزرسانی کند.
LifecycleOwner وظیفه دیگری را حل میکند: مدیریت اشتراکهای رویدادهای چرخه حیات، نه لغو کروتینها. برای کروتینها از lifecycleScope استفاده میشود که کروتینهای راهاندازی شده را هنگام نابودی LifecycleOwner به طور خودکار لغو میکند.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید