الخلاصة
App Lifecycle هو آلة حالات محدودة تصف جميع الحالات الممكنة للتطبيق المحمول والتحولات بينها. تحدد كل حالة ما إذا كان التطبيق يمكنه تنفيذ الكود أو عرض واجهة المستخدم أو استهلاك الموارد. iOS وAndroid لهما نماذج متشابهة ولكن ليست متطابقة — الاختلافات ناتجة عن بنية نظام التشغيل: iOS يستخدم تحكماً صارماً في الذاكرة (حالة suspended)، بينما Android يستخدم إدارة مرنة للعمليات عبر onSaveInstanceState.
في iOS، ترتبط دورة الحياة ارتباطاً وثيقاً بالمقدمة/الخلفية: التطبيق إما نشط أو معلق. في Android، دورة الحياة أكثر تفصيلاً — تمر Activity/نافذة بـ 6+ حالات، وللعملية نفسها دورة حياة إضافية عبر ProcessLifecycleOwner. التطبيقات الحديثة (منذ 2024) تستخدم بشكل متزايد أنماط بنية تعتمد على دورة الحياة: SwiftUI Lifecycle (iOS 16+) عبر بيئة .scenePhase، Compose Lifecycle عبر LifecycleEventObserver. هذه الأنماط تتعامل تلقائياً مع تبديل السياق وتمنع تسرب الذاكرة. وفقاً لـ Google، فإن المعالجة الصحيحة لدورة الحياة في Android تقلل استهلاك الذاكرة بنسبة 30–40 % أثناء العمل في الخلفية.
في iOS، تتم إدارة دورة حياة التطبيق من خلال الفئة UIApplicationDelegate (AppDelegate). الطرق الرئيسية: application(_:didFinishLaunchingWithOptions:) — التهيئة عند الإطلاق الأول؛ applicationDidBecomeActive — التطبيق مرئي وجاهز للتفاعل؛ applicationWillResignActive — الانتقال إلى الحالة غير النشطة (مكالمة واردة، إغلاق ستارة الإشعارات)؛ applicationDidEnterBackground — التطبيق مخفي، ~5 ثوانٍ لحفظ البيانات؛ applicationWillEnterForeground — العودة من الخلفية؛ applicationWillTerminate — الإنهاء (يُستدعى فقط للتطبيقات القديمة بدون suspended).
بدءاً من iOS 13، قدمت Apple SceneDelegate (UISceneDelegate) لدعم التطبيقات متعددة النوافذ على iPad وmacOS Catalyst. يدير SceneDelegate دورة حياة كل مشهد (نافذة) فردي: scene(_:willConnectTo:options:) — إنشاء المشهد؛ sceneDidBecomeActive — المشهد نشط؛ sceneWillResignActive — المشهد يفقد التركيز؛ sceneDidEnterBackground — المشهد مخفي. يتولى AppDelegate الأحداث العالمية (تحميل البيانات، إشعارات الدفع)، بينما يتولى SceneDelegate حالة واجهة المستخدم لكل نافذة. في SwiftUI، تتم إدارة دورة الحياة من خلال قيمة البيئة @Environment(\.scenePhase): .active، .inactive، .background — مما يوفر واجهة برمجة تطبيقات موحدة لكل من تطبيقات SwiftUI وUIKit.
في Android، تبدأ دورة الحياة بالفئة Application — singleton يتم إنشاؤه قبل أي Activity. طريقة Application.onCreate() هي نقطة الدخول الأولى، المستخدمة للتهيئة العالمية (Analytics، DI، Crash Reporting). بعد ذلك، يتم تشغيل Activity بالتسلسل: onCreate() → onStart() → onResume(). عند التصغير: onPause() → onStop() → onSaveInstanceState(). عند التدمير: onDestroy(). عند العودة: onRestart() → onStart() → onResume().
ProcessLifecycleOwner (من AndroidX Lifecycle 2.2+) يتتبع دورة حياة العملية بأكملها، وليس Activity فردية. يوفر حالتين: ON_RESUME (التطبيق في المقدمة) وON_STOP (التطبيق مخفي). يحل ProcessLifecycleOwner مشكلة «متى انتقل التطبيق إلى الخلفية» على مستوى العملية — وهذا أمر بالغ الأهمية لـ SDK والمكتبات والتطبيقات المعيارية. في Jetpack Compose، تتم إدارة دورة الحياة من خلال LifecycleEventObserver وcollectAsStateWithLifecycle، الذي يعلق تلقائياً جمع البيانات في وضع الخلفية. أضاف Android 14 (API 34) إشعار دورة حياة الخدمة الأمامية عبر Service.onTimeout — يجب أن تكتمل الخدمة في غضون 6 ساعات، وإلا يوقفها النظام قسراً.
| iOS | Android | الوصف |
|---|---|---|
| Not Running | — | التطبيق لم يتم تشغيله |
| didFinishLaunching | Application.onCreate | التهيئة الأولى عند الإطلاق |
| Active | onResume | التطبيق مرئي ويقبل الإدخال |
| Inactive | onPause | فقدان مؤقت للتركيز (مكالمة، ستارة إشعارات) |
| Background | onStop | التطبيق مخفي، يمكن تنفيذ الكود |
| Suspended | — | الكود لا يُنفذ، الذاكرة محجوزة |
| Will Terminate | onDestroy | التطبيق ينتهي |
الفرق الرئيسي: iOS ينقل التطبيق قسراً إلى Suspended (يتوقف الكود عن التنفيذ) بعد 5-10 ثوانٍ من الدخول إلى الخلفية. Android يسمح بالعمل في الخلفية (الخدمات، WorkManager) لفترة أطول، ولكن مع قيود من وضع Doze (Android 6+) وقيود الخلفية (Android 12+). ProcessLifecycleOwner في Android هو المكافئ لـ UIApplicationDidEnterBackgroundNotification في iOS، مع الفرق أنه يتم تفعيله عند أي انتقال إلى الخلفية، وليس فقط بعد فقدان التركيز.
تنفيذ أساسي لـ AppDelegate يعالج جميع حالات دورة الحياة. حفظ البيانات عند الانتقال إلى الخلفية وتحديث واجهة المستخدم عند العودة.
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
Analytics.shared.initialize()
return true
}
func applicationDidBecomeActive(_ application: UIApplication) {
NotificationCenter.default.post(name: .appDidBecomeActive, object: nil)
}
func applicationWillResignActive(_ application: UIApplication) {
NotificationCenter.default.post(name: .appWillResignActive, object: nil)
}
func applicationDidEnterBackground(_ application: UIApplication) {
CoreDataManager.shared.saveContext()
UserDefaults.standard.synchronize()
}
func applicationWillEnterForeground(_ application: UIApplication) {
NetworkManager.shared.refreshSession()
}
}
AppDelegate هو نقطة دورة الحياة المركزية. applicationDidEnterBackground هو طريقة حرجة: iOS يعطي ~5 ثوانٍ للحفظ. applicationDidBecomeActive — قم بتحديث واجهة المستخدم، أعد تشغيل الرسوم المتحركة. بالنسبة لـ SceneDelegate (iOS 13+)، يتم توزيع منطق دورة الحياة عبر المشاهد: sceneDidBecomeActive / sceneDidEnterBackground تديران النوافذ الفردية.
SceneDelegate لتطبيقات iPad متعددة النوافذ. كل مشهد له دورة حياة خاصة به، مستقلة عن النوافذ الأخرى.
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(
_ scene: UIScene,
willConnectTo session: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions
) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
window?.rootViewController = ViewController()
window?.makeKeyAndVisible()
}
func sceneDidBecomeActive(_ scene: UIScene) {
PlayerManager.shared.resume()
}
func sceneDidEnterBackground(_ scene: UIScene) {
PlayerManager.shared.pause()
CoreDataManager.shared.saveContext()
}
func sceneDidDisconnect(_ scene: UIScene) {
PlayerManager.shared.cleanup()
}
}
SceneDelegate يدير دورة حياة مشهد فردي. sceneDidBecomeActive / sceneDidEnterBackground هما معادلا طرق AppDelegate لنافذة محددة. يُستدعى sceneDidDisconnect عند إغلاق مشهد (أغلق المستخدم نافذة على iPad). للتوافق مع iOS 12 والإصدارات الأقدم، يجب على AppDelegate تكرار منطق SceneDelegate. في iOS 17+، يمكنك استخدام @Observable للإيقاف/الاستئناف التلقائي للمهام بناءً على scenePhase.
يتتبع ProcessLifecycleOwner متى يكون التطبيق في المقدمة/الخلفية على مستوى العملية. هذا هو النهج الأمثل لإدارة دورة الحياة العالمية.
import android.app.Application
import androidx.lifecycle.ProcessLifecycleOwner
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
class MainApplication : Application() {
override fun onCreate() {
super.onCreate()
ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifecycleObserver())
}
}
class AppLifecycleObserver : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onEnterForeground() {
Analytics.shared.onForeground()
NetworkMonitor.shared.start()
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onEnterBackground() {
Analytics.shared.onBackground()
NetworkMonitor.shared.stop()
}
}
ProcessLifecycleOwner هو الطريقة الصحيحة الوحيدة لتتبع الانتقال إلى الخلفية على مستوى التطبيق. ON_START يُفعّل عندما يصبح التطبيق مرئياً (المقدمة)، ON_STOP — عندما يكون مخفياً تماماً (الخلفية). على عكس دورة حياة Activity، فإن ProcessLifecycleOwner غير مرتبط بشاشة محددة. بالنسبة لـ Jetpack Compose، استخدم LifecycleResumeEffect أو collectAsStateWithLifecycle بدلاً من المراقبة اليدوية.
ViewModel + Lifecycle هي البنية الصحيحة لنظام Android لإدارة دورة الحياة. يتم تنظيف ViewModel تلقائياً عند onDestroy، مما يمنع تسرب الذاكرة.
import androidx.lifecycle.ViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
class TimerViewModel : ViewModel() {
private val _time = MutableLiveData<Long>()
val time: LiveData<Long> = _time
private var startTime = System.currentTimeMillis()
init {
updateTime()
}
private fun updateTime() {
_time.value = System.currentTimeMillis() - startTime
}
override fun onCleared() {
super.onCleared()
Logger.d("ViewModel cleared — تحرير الموارد")
}
}
// في Activity
class TimerActivity : AppCompatActivity() {
private val viewModel: TimerViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Logger.d("Activity created")
}
override fun onResume() {
super.onResume()
viewModel.time.observe(this) { Logger.d("Time: $it") }
}
override fun onPause() {
super.onPause()
Logger.d("Activity paused — إيقاف الرسوم المتحركة")
}
override fun onDestroy() {
super.onDestroy()
Logger.d("Activity destroyed — تنظيف")
}
}
ViewModel يبقى بعد تدوير الشاشة ويُدمر فقط عند إنهاء Activity. onCleared() هو المكان لتحرير الموارد وإلغاء الاشتراك من التدفقات. LiveData يوقف المراقبة تلقائياً عند onPause ويستأنفها عند onResume — وهذا يوفر حماية ضد التسرب والأعطال أثناء العمل في الخلفية. في Compose، استخدم collectAsStateWithLifecycle() لنفس الغرض.
الأسئلة الشائعة
عند التصغير، ينتقل التطبيق من نشط إلى غير نشط (لفترة وجيزة)، ثم إلى الخلفية. بعد بضع ثوانٍ، قد ينقله النظام إلى suspended — يتوقف الكود عن التنفيذ، الذاكرة محجوزة. عندما تكون الذاكرة منخفضة، ينهي النظام التطبيق المعلق (لا يتم استدعاء willTerminate). احفظ بياناتك في applicationDidEnterBackground — هذه هي آخر نقطة مضمونة للحفظ.
الحد الأدنى الإلزامي: applicationDidEnterBackground — حفظ بيانات المستخدم؛ applicationWillEnterForeground — تحديث واجهة المستخدم؛ في Android onPause — إيقاف الرسوم المتحركة/أجهزة الاستشعار. ProcessLifecycleOwner يبسط المعالجة: onResume — onPause للمقدمة، onStart — onStop للرؤية. قم بمعالجة الحالات الأخرى حسب الحاجة — ليست كل الحالات حرجة لكل تطبيق.
AppDelegate هو المفوض العالمي للتطبيق بأكمله (الإطلاق، الانتقال إلى الخلفية). SceneDelegate (iOS 13+) يدير دورة حياة نافذة فردية (مشهد) — في تطبيقات iPad متعددة النوافذ، كل مشهد له دورة حياة خاصة به. بالنسبة لـ iOS 12 والإصدارات الأقدم، تتم إدارة دورة الحياة بالكامل عبر AppDelegate. مع iPadOS 16+، SceneDelegate إلزامي لـ Stage Manager.
ProcessLifecycleOwner هو مكون من AndroidX Lifecycle يتتبع دورة حياة التطبيق بأكمله (العملية)، وليس Activity فردية. يوفر حدثين رئيسيين: ON_RESUME (التطبيق في المقدمة) وON_STOP (التطبيق في الخلفية). يُستخدم لتهيئة/تنظيف SDK والتحليلات ومراقبي الشبكة — أي شيء يجب أن يستجيب لانتقال التطبيق إلى الخلفية، بغض النظر عن الشاشة الحالية.
في Jetpack Compose، استخدم LifecycleEventObserver عبر LocalLifecycleOwner.current.lifecycle أو دالة collectAsStateWithLifecycle(). لشاشات Compose، استخدم LifecycleResumeEffect — مشابه لـ DisposableEffect، الذي يعمل عند onResume ويتم تنظيفه عند onPause. lifecycleScope.launchWhenResumed — كوروتين يتم تعليقه تلقائياً في الخلفية.
الملخص
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.