onStart هي طريقة من دورة حياة Android يتم استدعاؤها عندما يصبح Activity أو Fragment مرئياً للمستخدم. في هذه اللحظة، تظهر الشاشة على عرض الجهاز، لكنها لا تستطيع بعد التفاعل مع المستخدم — ينعدم تركيز الإدخال حتى يتم استدعاء onResume. تعتبر طريقة onStart مثالية لتسجيل مستمعي النظام، الاتصال بخدمات تحديد المواقع الجغرافية، وتشغيل الرسوم المتحركة التي يجب أن تعمل طالما المكون مرئي على الشاشة. اقرأ المزيد عن دورة حياة Activity الكاملة في المقال Activity Lifecycle.
الرئيسية
onStart هي الطريقة الثانية في دورة حياة Activity، يتم استدعاؤها بواسطة النظام بعد onCreate (أو بعد onRestart عند العودة من حالة التوقف). في لحظة استدعاء onStart، يصبح Activity أو Fragment مرئياً على الشاشة. يرى المستخدم الواجهة، لكن الشاشة ليست جاهزة بعد للتفاعل — سيظهر تركيز الإدخال فقط بعد onResume.
طريقة onStart تدخل في «العمر المرئي» (visible lifetime) لـ Activity — الفاصل الزمني بين onStart و onStop. خلال هذه الفترة، قد يكون Activity مغطى جزئياً بنوافذ أخرى (مثل Activity شفاف أو نافذة حوار)، لكن واجهة UI الخاصة به تظل مرئية. هذا يميز العمر المرئي عن «العمر في المقدمة» (onResume — onPause)، عندما يكون لدى Activity تركيز إدخال كامل.
فهم هذا التسلسل الهرمي ثلاثي المستويات أمر بالغ الأهمية للتوزيع الصحيح للكود. onCreate — تهيئة لمرة واحدة، onStart — توصيل الموارد المرئية، onResume — وصول حصري إلى الموارد الحصرية. المطور الذي يخلط بين هذه المستويات يخاطر بإنشاء تسريبات للذاكرة أو سلوك تطبيق غير صحيح عند التبديل بين الشاشات.
في Activity، يتم استدعاء onStart في كل مرة تظهر فيها الشاشة على العرض — سواء عند التشغيل الأول (بعد onCreate) أو عند العودة من الخلفية (بعد onRestart). على عكس onCreate، يمكن استدعاء onStart مرات متعددة خلال عمر مثيل Activity، لذلك يتم وضع الكود الذي يجب تنفيذه في كل مرة تظهر فيها الشاشة هنا.
class DashboardActivity : AppCompatActivity() {
private val connectivityReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val isConnected = ... // التحقق من ConnectivityManager
binding?.statusIndicator?.setColor(
if (isConnected) Color.GREEN else Color.RED
)
}
}
override fun onStart() {
super.onStart()
registerReceiver(
connectivityReceiver,
IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
)
SensorManager.getInstance().registerStepCounter()
}
override fun onStop() {
unregisterReceiver(connectivityReceiver)
SensorManager.getInstance().unregisterStepCounter()
super.onStop()
}
}
القاعدة الأساسية: جميع الموارد المتصلة في onStart يجب تحريرها في onStop. هذا يضمن أنه عندما يكون Activity مخفياً عن الشاشة، فإنه لا يستهلك البطارية، ولا يستمع لأحداث النظام، ولا يشغل الذاكرة. يحتوي Android Studio على قواعد lint تحذر من تسجيل BroadcastReceiver دون إلغاء تسجيل مماثل.
onStart في Fragment مرتبط بشكل وثيق بدورة حياة Activity الحاوية. يتلقى Fragment استدعاء onStart بعد أن يتلقى Activity الذي يحتويه onStart. ومع ذلك، إذا تمت إضافة Fragment في وضع مؤجل (FragmentTransaction.commit() دون addToBackStack)، فقد يتم استدعاء onStart مع تأخير.
class MapFragment : Fragment() {
private var mapView: MapView? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
mapView = MapView(requireContext())
return mapView!!
}
override fun onStart() {
super.onStart()
mapView?.onStart()
LocationService.connect(requireContext())
}
override fun onStop() {
mapView?.onStop()
LocationService.disconnect()
super.onStop()
}
}
خصوصية Fragment.onStart: إذا كان Fragment في ViewPager مع offscreenPageLimit = 1، فإن الأجزاء المجاورة ستتلقى أيضاً onStart قبل أن تصبح مرئية. هذا قد يؤدي إلى تسجيل مبكر للمستمعين. لمثل هذه الحالات، استخدم طريقة setUserVisibleHint() أو تحقق من isVisible داخل onStart لتسجيل المستمعين فقط للأجزاء المرئية فعلياً.
الفرق الرئيسي بين onStart و onResume هو مستوى نشاط الشاشة. يشير onStart إلى أن Activity مرئية على الشاشة ولكنها ليست بالضرورة في المقدمة. يشير onResume إلى أن Activity في المقدمة ولديها تركيز إدخال. يتم توضيح الفرق بمثال نافذة حوار: عندما يظهر Dialog فوق Activity، تفقد Activity onResume (يتم استدعاء onPause) ولكنها تظل مرئية — لا يتم استدعاء onStart/onStop.
يوضح جدول المقارنة بوضوح في أي السيناريوهات يتم استدعاء كل طريقة:
| السيناريو | onStart | onResume |
|---|---|---|
| تشغيل التطبيق | يتم استدعاؤه | يتم استدعاؤه |
| Dialog مفتوح فوق Activity | لا يتم استدعاؤه | onPause (فقدان التركيز) |
| الضغط على زر الرئيسية | onStop (مخفي) | onPause → onStop |
| العودة من الحديثة | onStart (مرئي) | onResume (تركيز) |
| تدوير الشاشة | onCreate → onStart | → onResume |
| مكالمة واردة | onStop (مخفي) | onPause → onStop |
هذا الجدول يساعد المطور في تحديد أي طريقة يضع فيها كوداً معيناً. على سبيل المثال، إذا كان التطبيق يجب أن يوقف تشغيل الفيديو عند أي تغطية للشاشة (حتى مع حوار)، يتم وضع الكود في onPause. إذا كان يجب أن يتوقف الفيديو فقط عند إخفاء الشاشة بالكامل — يتم وضع الكود في onStop.
onStart هو المكان الأمثل لتسجيل المستمعين الذين يجب أن يعملوا فقط عندما يكون Activity مرئياً على الشاشة. هذا يتعلق بثلاثة أنواع رئيسية من مكونات النظام: BroadcastReceiver لأحداث النظام، LocationListener لتحديد المواقع الجغرافية، و SensorListener لأجهزة الاستشعار.
BroadcastReceiver يتم تسجيله ديناميكياً عبر Context.registerReceiver() في onStart وإلغاء تسجيله في onStop عبر unregisterReceiver(). التسجيل الديناميكي أفضل من التسجيل الثابت (في البيان) لأنه يحد من عمر المستقبل بفترة رؤية Activity — التطبيق لا يستيقظ من رسائل البث النظامية عندما يكون Activity مخفياً.
private val batteryReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent) {
val level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
binding?.batteryText?.text = "$level%"
}
}
override fun onStart() {
super.onStart()
registerReceiver(batteryReceiver, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
}
override fun onStop() {
unregisterReceiver(batteryReceiver)
super.onStop()
}
تحديد المواقع الجغرافية وأجهزة الاستشعار عمليات تستهلك موارد كثيرة. طلب تحديثات GPS في onStart والإلغاء في onStop يضمن أن التطبيق لا يستهلك البطارية عندما تكون الشاشة مخفية. للضبط الدقيق، استخدم requestLocationUpdates بفاصل زمني ومسافة أدنى — مثلاً 10 ثوان و 10 أمتار، مما يعطي توازناً مثالياً بين الدقة واستهلاك الطاقة.
تشغيل الرسوم المتحركة في onStart، بدلاً من onCreate، يضمن أن الرسوم المتحركة تبدأ في كل مرة تظهر فيها الشاشة. إذا قمت بتشغيل رسم متحرك في onCreate، فسيعمل فقط عند إنشاء Activity لأول مرة، وليس عند العودة من الخلفية. يتم استدعاء onStart في كل مرة يصبح فيها Activity مرئياً، مما يجعله المكان المثالي لتشغيل الرسوم المتحركة الدورية والانتقالات.
private lateinit var pulseAnimator: ValueAnimator
override fun onStart() {
super.onStart()
pulseAnimator.start()
binding?.loadingIndicator?.animate()?.alpha(1f)?.start()
}
override fun onStop() {
pulseAnimator.cancel()
binding?.loadingIndicator?.animate()?.cancel()
super.onStop()
}
للرسوم المتحركة التي تستخدم ObjectAnimator أو ValueAnimator، من المهم استدعاء cancel() في onStop. إذا استمر الرسم المتحرك في العمل بعد إخفاء Activity، فإنه يستهلك موارد GPU و CPU بدون فائدة، مما يقلل أداء الجهاز ويسرع استنزاف البطارية. يتيح Android Studio Profiler (رسم GPU) تتبع الرسوم المتحركة النشطة واكتشاف التسريبات.
قاعدة الزوج onStart/onStop تنطبق أيضاً على العمل مع الكاميرا للمعاينة (CameraX). فتح الكاميرا في onStart وإغلاقها في onStop يضمن أن الكاميرا غير محجوبة لتطبيقات أخرى عندما لا يكون تطبيقك مرئياً على الشاشة. انتهاك هذه القاعدة هو سبب شائع للمراجعات السلبية في Google Play.
الأسئلة الشائعة
onStart — للمستمعين الذين يجب أن يعملوا طالما الشاشة مرئية (BroadcastReceiver، LocationListener، SensorListener). onResume — للموارد التي تتطلب وصولاً حصرياً (الكاميرا، التقاط الفيديو، التعرف على الكلام). مستمعو أحداث النظام لا يحتاجون وصولاً حصرياً ويمكنهم العمل مع تغطية جزئية — يتم تسجيلهم في onStart. يجب أن تكون الكاميرا نشطة فقط مع التركيز الكامل — يتم فتحها في onResume.
يتم استدعاء onStart دائماً إذا انتقل Activity إلى حالة مرئية. السيناريو الوحيد بدون onStart — يتم إنشاء Activity وإنهاؤه فوراً (مثلاً بسبب خطأ في onCreate). في هذه الحالة، يتم استدعاء onDestroy مباشرة بعد onCreate. لكن هذا سيناريو طارئ لا يجب أن يحدث في كود مكتوب بشكل صحيح.
نعم، قد لا يتلقى onStart onResume إذا تم فتح Activity آخر أو نافذة شفافة فوراً فوق Activity. على سبيل المثال، إذا تم تشغيل شاشة تفويض بعد onCreate (Activity A → Activity B)، في Activity A يتم استدعاء onStart، لكن onResume لا — يتلقى فوراً onPause → onStop عند التغطية بالشاشة B.
يمكن استدعاء onStart مرات متعددة خلال عمر مثيل Activity. في كل مرة ينتقل Activity من حالة مخفية (onStop) إلى حالة مرئية، يتم استدعاء onStart. عملياً، مع الاستخدام النشط للتطبيق، يمكن استدعاء onStart عشرات أو مئات المرات في الجلسة.
تحميل البيانات في onStart مبرر إذا كانت البيانات يجب أن تُحدَّث في كل مرة تظهر فيها الشاشة. مثلاً، قائمة الأخبار أو قائمة الإشعارات. لكن يجب أن يكون التحميل غير متزامن — عبر coroutines مع lifecycleScope، لتجنب حظر مسار UI. للبيانات التي لا تتغير بين ظهور الشاشة، يكفي تحميلها مرة واحدة في onCreate.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.