LifecycleOwner هي واجهة رئيسية من مكتبة Android Jetpack تعلن أن الكائن يمتلك دورة حياة وتوفر الوصول إليها عبر الطريقة getLifecycle(). تشكل أساس هندسة المكونات في تطبيقات Android الحديثة، مما يسمح بفصل منطق دورة الحياة عن التنفيذ المحدد لـ Activity أو Fragment. وفقًا لـ Google I/O 2024، أكثر من 85% من المشاريع الجديدة على Android تستخدم LifecycleOwner لإدارة الاشتراكات ومنع تسرب الذاكرة. هذه الواجهة هي أساس LiveData و ViewModel ومكونات Jetpack الأخرى، مما يضمن تنفيذ آمن للكود فقط عندما يكون المكون في حالة نشط.
النقاط الرئيسية
LifecycleOwner هي واجهة من حزمة androidx.lifecycle تحتوي على طريقة واحدة هي getLifecycle()، والتي تعيد كائن Lifecycle. يتبع هذا الكائن الحالة الحالية للمكون (CREATED، STARTED، RESUMED، DESTROYED) ويخطر جميع المراقبين المشتركين عند تغيرها. LifecycleOwner هي جزء من Architecture Components وتندرج في مكتبة lifecycle-runtime.
الهدف الرئيسي للواجهة هو توحيد الوصول إلى دورة الحياة. قبل Jetpack، كان المطورون يشتركون ددويًا في onStart ويلغون الاشتراك في onStop، ما أدى إلى تكرار الكود والأخطاء. يحل LifecycleOwner هذه المشكلة من خلال توفير آلية موحدة لجميع مكونات Android. بدلاً من استدعاء طرق دورة الحياة صراحة، يشترك المطور في Lifecycle مرة واحدة، وتصل الإشعارات تلقائيًا.
تُصرح الواجهة في Kotlin كواجهة وظيفية بطريقة مجردة واحدة:
interface LifecycleOwner {
val lifecycle: Lifecycle
}
بفضل الطابع الوظيفي للواجهة، من السهل تنفيذها باستخدام مفوض أو lambda. هذا مفيد بشكل خاص لإنشاء Custom Views وفئات ViewModel التي تحتاج إلى الاستجابة لتغيرات دورة حياة المضيف. يوفر كائن Lifecycle المحصل عليه من getLifecycle() طرقي addObserver و removeObserver لإدارة الاشتراكات.
LifecycleOwner يعمل بالاشتراك مع فئتين رئيسيتين: Lifecycle و LifecycleObserver. يخزن Lifecycle الحالة الحالية للمكون كتعداد State (INITIALIZED، CREATED، STARTED، RESUMED، DESTROYED) ويتبع الانتقالات بينها. عندما تتغير الحالة، يخطر Lifecycle جميع المراقبين المسجلين من خلال استدعاء الطرق الموسومة المناسبة. يطلق على هذه الآلية اسم “واعية بدورة الحياة” — يتم تنفيذ الكود فقط عندما يكون المكون في حالة مناسبة.
تعتمد آلية توصيل الأحداث على نمط Observer. يعمل LifecycleOwner كـ Observable، وتعمل تطبيقة LifecycleObserver كـ Observer. عندما تغير Activity أو Fragment حالتها (onCreate → onStart → onResume → onPause → onStop → onDestroy)، تخطر Lifecycle عبر آلية ReportFragment الداخلية، التي تضاف تلقائيًا إلى نظام AndroidX. لا يحتاج المطور إلى استدعاء طرق Lifecycle يدويًا — كل شيء يحدث تلقائيًا.
| حالة Lifecycle | الحدث | طريقة دورة الحياة في Android |
|---|---|---|
| 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 الحديث بالطرق الصريحة. توصي Google بالنهج الثاني منذ 2022، حيث يوفر أمانًا أفضل للأنواع ويتجنب الانعكاس المستخدم في النهج القائم على التعليقات. يتطلب 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 كوسيطة. يسمح هذا للمراقب بالوصول إلى سياق المكون المنفذ دون الحاجة إلى تمريره بشكل منفصل. هذا النهج يجعل الكود أكثر نمطية وقابلية للاختبار — المراقب لا يعتمد على تطبيق محدد لـ Activity أو Fragment، بل يعمل مع التجريد LifecycleOwner.
الطريقة القديمة باستخدام التعليق @OnLifecycleEvent لا تزال موجودة في المشاريع القديمة، ولكن لا يوصى باستخدامها للكود الجديد. الانعكاس المطلوب لمعالجة التعليقات يضيف عبئاً وقد يؤدي إلى أخطاء لا تُكتشف في وقت الترجمة. توصي Google رسميًا بالترحيل إلى DefaultLifecycleObserver.
// نهج قديم — غير موصى به للمشاريع الجديدة
class MyLegacyObserver : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onStart() {
startLocationUpdates()
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onStop() {
stopLocationUpdates()
}
}
لنهج التعليقات عيب كبير: عدم التحكم في عمر المراقب. إذا نسي المطور إلغاء اشتراك المراقب عند إتلاف LifecycleOwner، يبقى كائن المراقب في الذاكرة حتى يعمل مجمع القمامة. يحل DefaultLifecycleObserver هذه المشكلة — المراقب مرتبط بـ Lifecycle ويلغي اشتراكه تلقائيًا عند الانتقال إلى حالة DESTROYED.
منذ AppCompat 1.1.0 و AndroidX Fragment 1.2.0، جميع كيانات Activity و Fragment التي ترث AppCompatActivity أو Fragment هي تلقائيًا LifecycleOwners. هذا يعني أن الطريقة getLifecycle() متاحة بالافتراضي، والاشتراك في أحداث دورة الحياة يعمل دون إعداد إضافي. يكتفي المطور باستدعاء lifecycle.addObserver() من أي مكان في Activity أو Fragment.
لننظر إلى مثال دمج LifecycleOwner في Activity:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycle.addObserver(LocationObserver(this))
}
}
في هذا المثال، lifecycle هي خاصية تمديد متاحة بفضل AndroidX Activity. سيتلقى LocationObserver تلقائيًا إشعارات حول البدء (ON_START) والإيقاف (ON_STOP) لـ Activity. عند تدوير الشاشة، يتم إشعار المراقب بـ ON_DESTROY ثم ON_CREATE، مما يسمح بمعالجة تغييرات التهيئة بشكل صحيح دون كود إضافي.
Fragment ينفذ LifecycleOwner عبر واجهته، و Lifecycle الخاص به مرتبط بدورة حياة Fragment، ليس بدورة حياة Activity الأصلية. هذا مهم: ينتقل Lifecycle لـ Fragment إلى DESTROYED عندما يتم إزالة Fragment من المعاملة، بينما قد تظل Activity في RESUMED. يسمح هذا الاختلاف للمراقبين بالاشتراك بشكل منفصل في دورة حياة كل مكون.
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، حيث يمكن إنشاء وتدمير Fragments ديناميكيًا. كانت الإدارة اليدوية للاشتراكات في هذا السيناريو ستكون معقدة جدًا وعرضة للأخطاء.
يمكن تنفيذ واجهة LifecycleOwner في أي فئة لديها دورة حياة. هذا مفيد لـ Custom Views و Services وحتى 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 يعمل كمخزن للحالة. يجب أن تستدعي المكونة الأصلية (مثل Activity) طريقتي onStart/onStop عندما تصبح Custom View مرئية أو تختفي. يحسب LifecycleRegistry تلقائيًا الأحداث المطلوبة للانتقال بين الحالات ويخطر جميع المراقبين المشتركين.
عند تنفيذ LifecycleOwner مخصص، من المهم اتباع القاعدة: يجب تحديث حالة LifecycleRegistry في آخر الطريقة المناسبة لدورة الحياة، بعد جميع العمليات الأخرى. يضمن هذا أن يتلقى المراقبون إشعارًا عندما يكون المكون جاهزًا بالكامل للحالة الجديدة. استخدام LifecycleRegistry.createUnsafe كبديل ممكن أيضًا، ولكنه يتطلب الحذر مع الخيوط.
LifecycleOwner هو أساس عدة مكونات رئيسية في Android Jetpack. LiveData تستخدم LifecycleOwner لتحديد الحالة النشطة وإلغاء الاشتراك تلقائيًا عند إتلاف المكون. ViewModel لا تنفذ LifecycleOwner مباشرة، ولكن يمكنها الحصول على Lifecycle عبر SavedStateHandle. 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 كائن LifecycleOwner في الطريقة observe() لأنها تضمن أن تحديثات واجهة المستخدم تحدث فقط في الحالة النشطة. إذا كانت Activity في الخلفية، تحتفظ LiveData بآخر قيمة ولكن لا تخطر المراقب. عند العودة إلى RESUMED، يتلقى المراقب القيمة الحالية دون طلبات إضافية للشبكة أو قاعدة البيانات.
DataBinding تستخدم أيضًا LifecycleOwner لربط الحقول القابلة للمراقبة بدورة حياة Activity أو Fragment. يساعد هذا في تجنب تسرب الذاكرة في مزيج ViewModel + DataBinding — جميع الاشتراكات تُنظف تلقائيًا عند إتلاف LifecycleOwner. هذا النهج يجعل الكود تصريحيًا وآمنًا.
يتطلب الاستخدام الصحيح لـ LifecycleOwner اتباع عدة قواعد رئيسية. الأولى والأهم: قم دائمًا باشتراك المراقب في onCreate/onViewCreated، وليس لاحقًا. يضمن هذا أن يتلقى المراقب حالة 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 في Fragments وهو النهج الموصى به من Google للعمل مع تدفقات البيانات غير المتزامنة في مكونات واجهة المستخدم.
توصية مهمة أخرى: لا تفرط في استخدام LifecycleObserver للمنطق غير المرتبط بدورة الحياة. إذا كان المكون يحتاج إلى تنفيذ إجراء في حالة محددة ولكنه لا يتطلب إلغاء الاشتراك عند الإتلاف، فمن الأفضل استخدام استدعاءات صريحة للطرق في onStart/onStop. LifecycleObserver مبرر للمكونات طويلة العمر (LocationListener، SensorManager) حيث تكون الإدارة اليدوية للاشتراكات معقدة وعرضة للأخطاء.
الأسئلة الشائعة
LifecycleOwner هي واجهة تعلن أن الكائن لديه دورة حياة. Lifecycle هو فئة تخزن الحالة الحالية وتدير المراقبين. توفر LifecycleOwner Lifecycle عبر getLifecycle().
لا، Lifecycle يلغي اشتراك جميع المراقبين تلقائيًا عند الانتقال إلى DESTROYED. هذه واحدة من المزايا الرئيسية لـ LifecycleOwner — لا يحتاج المطور إلى استدعاء removeObserver يدويًا في onDestroy.
Fragment ينفذ LifecycleOwner عبر واجهة الفراغمنتات من AndroidX. يرتبط Lifecycle الخاص به بدورة حياة Fragment بشكل منفصل عن Activity. يسمح هذا للمراقب بالتفاعل تحديدًا مع أحداث Fragment، ليس مع أحداث Activity الأصلية.
نعم، يتم استخدام LifecycleRegistry لهذا الغرض. يجب على Custom View تنفيذ واجهة LifecycleOwner وتحديث حالة LifecycleRegistry يدويًا عند تغير الرؤية أو عند الارتباط بالنافذة.
LifecycleOwner يحل مشكلة مختلفة: إدارة الاشتراكات في أحداث دورة الحياة، ليس إلغاء الكوروتين. للكوروتين، يتم استخدام lifecycleScope، الذي يلغي تلقائيًا الكوروتين المشغلة عند إتلاف LifecycleOwner.
الملخص
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.