onStop — إخفاء النشاط في دورة حياة Android

المؤلف: IT Sectr نُشر: 2026-03-04 وقت القراءة: 9 دق

onStop — طريقة من دورة حياة النشاط في Android، يتم استدعاؤها من قبل النظام عندما يتوقف النشاط عن الظهور للمستخدم. ينتقل النشاط إلى الحالة Stopped بعد أن يغطيه نشاط جديد بالكامل، أو عند تصغير التطبيق. في طريقة onStop، يجب على المطور إيقاف الرسوم المتحركة، تحرير موارد الكاميرا وأجهزة الاستشعار، وحفظ مسودات البيانات المدخلة. وفقًا لـ Android Vitals (Google, 2025)، فإن المعالجة الصحيحة لـ onStop تقلل عدد حالات ANR (التطبيق لا يستجيب) عند تصغير التطبيق بنسبة 35%. بعد onStop، يمكن للنظام استدعاء onRestart (العودة إلى الشاشة) أو onDestroy (الإنهاء الكامل). توثق Android Developers دورة حياة النشاط وتصف onStop كحد بين الحالة المرئية وغير المرئية.

الخلاصة

  • onStop — طريقة يتم استدعاؤها عند فقدان النشاط للرؤية بالكامل، ولكن النشاط لا يزال في الذاكرة.
  • بعد onStop، ينتقل النشاط إلى الحالة Stopped — حي في الذاكرة، لكن غير مرئي ولا يتفاعل مع المستخدم.
  • يمكن للنظام استدعاء onRestart ← onStart ← onResume عند العودة إلى النشاط أو onDestroy عند الإنهاء.
  • في onStop، يجب تحرير الموارد: إيقاف الرسوم المتحركة، تعطيل أجهزة الاستشعار والكاميرا، حفظ البيانات الوسيطة.
  • التنفيذ الصحيح لـ onStop هو عامل رئيسي في استقرار التطبيق أثناء تعدد المهام والتصغير.

ما هو onStop في Android؟

onStop — طريقة رد اتصال من فئة AppCompatActivity (وسابقتها Activity)، يتم استدعاؤها بواسطة نظام تشغيل Android عندما يتوقف النشاط عن الظهور بالكامل للمستخدم. في هذه اللحظة، يكون النشاط مخفيًا بواسطة نشاط آخر أو نافذة حوار أو مشغل النظام أو شاشة القفل. من منظور دورة الحياة، يأتي onStop بعد onPause ويشير إلى أن النشاط لم يعد مرئيًا على الشاشة، على الرغم من أن كائن النشاط وحالته لا يزالان في الذاكرة.

عندما ينتقل النشاط إلى الحالة Stopped (متوقف)، يحتفظ بحالته في ذاكرة الوصول العشوائي — تظل جميع الحقول والتسلسل الهرمي للعرض وViewModel قابلة للوصول. هذا يميز Stopped عن الحالة Destroyed (مدمر)، حيث يتم حذف النشاط بالكامل. يمكن لواجهة النظام إنهاء عملية التطبيق في الحالة Stopped عند نقص الذاكرة — وهذا ما يسمى موت العملية. يجب على المطور حفظ البيانات الحرجة (المسودات، موضع التمرير) في onSaveInstanceState()، الذي يتم استدعاؤه قبل onStop، لضمان الاستعادة عند موت العملية.

وفقًا لوثيقة تعريف توافق Android (CDD) للإصدار 14+، فإن العملية في الحالة Stopped لها أولوية منخفضة للقتل بواسطة OOM Killer — أقل من العمليات في مرحلة الخلفية، لكن أعلى من العمليات المخزنة مؤقتًا. وفقًا لإحصائيات Google، تحدث 68% من حالات موت العملية عندما يكون النشاط في الحالة Stopped، وليس Paused.

متى يتم استدعاء onStop: السيناريوهات والترتيب

يتم استدعاء onStop عندما يفقد النشاط الرؤية بالكامل، بغض النظر عن السبب: بدء نشاط جديد فوق النشاط الحالي، تصغير التطبيق (الضغط على الصفحة الرئيسية)، قفل الشاشة، مكالمة واردة، أو فتح حوار النظام. في كل هذه الحالات، يتلقى النشاط أولاً onPause (فقدان جزئي للتركيز)، ثم onStop (فقدان كامل للرؤية).

السيناريوهات الرئيسية لاستدعاء onStop:

  • بدء نشاط جديد فوق النشاط الحالي — يتلقى النشاط الحالي onPause، ثم onStop؛ يمر النشاط الجديد بـ onCreate ← onStart ← onResume.
  • تصغير التطبيق (الصفحة الرئيسية) — ينتقل النشاط إلى onPause ← onStop خلال 200–300 مللي ثانية، ويبقى في الذاكرة في الحالة Stopped.
  • قفل الشاشة — يستدعي النظام onPause ← onStop لأن شاشة القفل تغطي النشاط بالكامل.
  • مكالمة واردة — يتم تشغيل تطبيق الهاتف (Dialer) فوق النشاط الحالي، وينتقل النشاط الحالي إلى onStop.
  • التبديل إلى تطبيق آخر (التطبيقات الحديثة) — يتم إخفاء النشاط، ويتلقى onStop، لكنه يبقى في ذاكرة التخزين المؤقت للعمليات.

من المهم أن نفهم أن onStop لا يتم استدعاؤه عند تدوير الشاشة — في هذه الحالة، يتم تدمير النشاط (onPause ← onStop ← onDestroy) وإعادة إنشائه (onCreate ← onStart ← onResume). الاستثناء هو العلم android:configChanges="orientation" في البيان، والذي يمنع إعادة إنشاء النشاط ويستدعي بدلاً من ذلك onConfigurationChanged().

onStop في دورة حياة النشاط

يحتل onStop مكانًا مركزيًا في تسلسل دورة حياة النشاط بين الحالة المرئية وغير المرئية. التسلسل الكامل: onCreate ← onStart ← onResume ← (حالة نشطة) ← onPause ← onStop ← onDestroy (أو onRestart ← onStart ← onResume عند العودة).

الحالةالطريقةالرؤيةالتفاعلالذاكرة
CreatedonCreateلالامخصصة
StartedonStartجزئيةلاكاملة
ResumedonResumeكاملةنعمكاملة
PausedonPauseجزئيةلاكاملة
StoppedonStopلالاكاملة*
DestroyedonDestroyلالامحررة

*في الحالة Stopped، يتم الاحتفاظ بالنشاط في الذاكرة ولكن قد يتم قتله بواسطة النظام عند نقص الموارد. أولوية قتل عمليات Stopped هي ما قبل الأخيرة، فوق العمليات الفارغة المخزنة مؤقتًا فقط.

onStop و onSaveInstanceState: يستدعي النظام onSaveInstanceState(Bundle) قبل onStop لحفظ حالة واجهة المستخدم الديناميكية. ي override المطور هذه الطريقة لحفظ قيم حقول الإدخال وموضع RecyclerView والعناصر المحددة في Bundle. حتى إذا لم يتم تدمير النشاط (المستخدم ببساطة صغر وعاد)، يتم تمرير Bundle إلى onCreate عند تغييرات التكوين. توصي Google بحفظ حالة واجهة المستخدم العابرة فقط — وليس بيانات المستودع أو ViewModel التي تعيش خارج النشاط.

ما الموارد التي يجب تحريرها في onStop

في onStop، يجب على المطور تحرير جميع الموارد التي ليست ضرورية عندما لا يكون النشاط مرئيًا. هذا يقلل من حمل البطارية ووحدة المعالجة المركزية والذاكرة، ويمنع أيضًا ANR عند العودة إلى النشاط.

ما يجب تحريره في onStop:

  • الرسوم المتحركة والانتقالات — إيقاف ObjectAnimator و ValueAnimator و ViewPropertyAnimator. الرسوم المتحركة العاملة في نشاط غير مرئي تهدر دورات GPU.
  • أجهزة الاستشعار — إلغاء الاشتراك من SensorManager (مقياس التسارع، الجيروسكوب، مقياس المغناطيسية). تستهلك أجهزة الاستشعار الطاقة حتى عندما يكون النشاط مخفيًا.
  • الكاميرا والميكروفون — تحرير Camera2 أو CameraX، إيقاف MediaRecorder. ترك الكاميرا نشطة والنشاط مخفي محظور بموجب سياسة Google Play.
  • LocationListener — إلغاء الاشتراك من FusedLocationProviderClient أو LocationManager. تحديد الموقع الجغرافي هو أكثر الموارد استهلاكًا للطاقة.
  • مستمعي الشبكة — إغلاق WebSocket، إلغاء طلبات HTTP غير الضرورية في الخلفية.
  • MediaPlayer و ExoPlayer — إيقاف أو إيقاف التشغيل مؤقتًا إذا كان لا يجب أن يستمر في الخلفية.

ما لا يجب فعله في onStop: لا تقم بتنفيذ عمليات طويلة — حفظ كميات كبيرة من البيانات في قاعدة البيانات، طلبات الشبكة، الحسابات المعقدة. يتم تنفيذ onStop على الخيط الرئيسي ويمنع العودة إلى النشاط. للعمليات الطويلة، استخدم WorkManager مع تأخير أو coroutines في viewModelScope. لا تحرر موارد ViewModel — ViewModel تبقى بعد onStop وستستخدم عند العودة.

الفرق بين onStop و onPause

يختلف onPause و onStop في درجة فقدان الرؤية ونطاق الإجراءات الإلزامية. يتم استدعاء onPause عند فقدان جزئي للتركيز (مثل فتح نافذة حوار أو قائمة النظام)، onStop — عند فقدان كامل للرؤية. هذا الاختلاف مهم لاختيار الموارد التي يجب تحريرها في كل مرحلة.

الخاصيةonPauseonStop
مستوى الرؤيةمرئي جزئيًاغير مرئي تمامًا
التركيزمفقودمفقود
وقت التنفيذحتى 500 مللي ثانيةحتى 5 ثوانٍ (مهلة ANR)
الموارد المطلوب تحريرهاالحرجة (الوسائط، الكاميرا)جميع غير المرئية (أجهزة الاستشعار، الرسوم المتحركة، الموقع)
الاستعادةonResumeonRestart ← onStart ← onResume
أولوية العمليةعالية (أمامية)متوسطة (خلفية)

القاعدة العامة: في onPause، حرر موارد النظام التي تؤثر فورًا على تجربة المستخدم لتطبيق آخر (الكاميرا، مشغل الوسائط)؛ في onStop — جميع الموارد الأخرى غير الضرورية عندما يكون النشاط مخفيًا. توصي Google بحفظ بيانات المستخدم الحرجة (مسودة البريد الإلكتروني، الإعدادات) في onPause، لأن onStop قد لا يتم استدعاؤه أثناء التبديل السريع.

onStop ← onRestart: العودة إلى الشاشة

عندما يعود المستخدم إلى نشاط مخفي، يستدعي النظام onRestart ← onStart ← onResume. تشير طريقة onRestart إلى أن النشاط يعود من الحالة Stopped. هذه مرحلة مهمة لاستعادة واجهة المستخدم والموارد التي تم تحريرها في onStop.

تسلسل الاستدعاءات عند العودة:

  • onRestart() — يتم إخطار النشاط بأنه سيتم عرضه مرة أخرى. الإجراءات النموذجية: إعادة تحميل البيانات، تحديث القوائم.
  • onStart() — يصبح النشاط مرئيًا ولكن ليس نشطًا بعد. هنا يتم إعادة تهيئة الموارد التي تم تحريرها في onStop.
  • onResume() — يحصل النشاط على التركيز ويكون جاهزًا للتفاعل. تبدأ الرسوم المتحركة، يتم تسجيل أجهزة الاستشعار.

إذا تم قتل عملية التطبيق بواسطة النظام في الحالة Stopped، يتم استدعاء onCreate بدلاً من onRestart، ويتم تمرير Bundle من onSaveInstanceState لاستعادة الحالة. هذا السيناريو (موت العملية) هو أحد أكثر أسباب الأخطاء شيوعًا في تطبيقات Android: يطبق المطورون onRestart لكنهم ينسون مراعاة الاستعادة عبر onCreate بعد موت العملية.

أمثلة كود مع onStop بلغة Kotlin

مثال 1: تنفيذ أساسي لـ onStop مع تحرير أجهزة الاستشعار

يوضح إلغاء الاشتراك الصحيح من أجهزة الاستشعار وإيقاف الرسوم المتحركة عند إخفاء النشاط. عند العودة إلى الشاشة، يتم استعادة الموارد في onStart.

kotlin
class MainActivity : AppCompatActivity() {
    private lateinit var sensorManager: SensorManager
    private var accelerometer: Sensor? = null
    private var rotationAnimator: ObjectAnimator? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
        accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
    }

    override fun onStart() {
        super.onStart()
        accelerometer?.let {
            sensorManager.registerListener(sensorListener, it, SensorManager.SENSOR_DELAY_NORMAL)
        }
        rotationAnimator = ObjectAnimator.ofFloat(findViewById(R.id.icon), "rotation", 0f, 360f)
        rotationAnimator?.apply {
            duration = 3000
            repeatMode = ValueAnimator.RESTART
            repeatCount = ValueAnimator.INFINITE
            start()
        }
    }

    override fun onStop() {
        super.onStop()
        sensorManager.unregisterListener(sensorListener)
        rotationAnimator?.cancel()
    }

    override fun onRestart() {
        super.onRestart()
        Log.d("MainActivity", "يعود النشاط من الحالة Stopped")
    }

    private val sensorListener = SensorEventListener { event, _ ->
        Log.d("MainActivity", "التسارع: x=${event.values[0]}، y=${event.values[1]}، z=${event.values[2]}")
    }
}

يسجل الكود مستشعر مقياس التسارع ويبدأ رسمًا متحركًا دورانيًا لا نهائيًا في onStart. في onStop، يتم إلغاء تسجيل المستشعر وإلغاء الرسم المتحرك — وهذا يمنع استنزاف البطارية عندما يكون النشاط مخفيًا. بعد العودة عبر onRestart ← onStart، يتم إعادة إنشاء الموارد.

مثال 2: onStop مع حفظ الحالة عبر SavedStateHandle

نهج حديث باستخدام ViewModel + SavedStateHandle. يتم حفظ بيانات النموذج تلقائيًا أثناء onStop دون معالجة يدوية لـ Bundle.

kotlin
class FormViewModel(
    private val savedStateHandle: SavedStateHandle
) : ViewModel() {
    var email: String
        get() = savedStateHandle["email"] ?: ""
        set(value) { savedStateHandle["email"] = value }

    var message: String
        get() = savedStateHandle["message"] ?: ""
        set(value) { savedStateHandle["message"] = value }
}

class FormActivity : AppCompatActivity() {
    private val viewModel: FormViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_form)
        Log.d("FormActivity", "onCreate: email=${viewModel.email}")
    }

    override fun onStop() {
        super.onStop()
        Log.d("FormActivity", "onStop: تم حفظ البيانات في SavedStateHandle")
    }
}

يقوم SavedStateHandle تلقائيًا بحفظ القيم في Bundle أثناء onSaveInstanceState، الذي يتم استدعاؤه قبل onStop. عند تدوير الشاشة أو موت العملية، يتم استعادة البيانات دون فقدان. توصي Google باستخدام SavedStateHandle للنماذج والمسودات بدلاً من onSaveInstanceState المباشر.

مثال 3: lifecycleScope للعمليات في onStop

استخدام lifecycleScope مع coroutines لحفظ البيانات بشكل غير متزامن أثناء الانتقال إلى onStop. يتم تشغيل coroutine على مرسل IO دون حظر الخيط الرئيسي.

kotlin
class NoteActivity : AppCompatActivity() {
    private val noteRepository = NoteRepository()

    override fun onStop() {
        lifecycleScope.launch(Dispatchers.IO) {
            val text = findViewById<EditText>(R.id.note_content).text.toString()
            noteRepository.saveDraft(text)
            withContext(Dispatchers.Main) {
                Log.d("NoteActivity", "تم حفظ المسودة في onStop")
            }
        }
        super.onStop()
    }
}

يتم إلغاء coroutine lifecycleScope.launch تلقائيًا إذا انتهت دورة حياة النشاط. يضمن استخدام Dispatchers.IO أن الكتابة إلى قاعدة البيانات أو الملف لا تمنع العودة إلى النشاط. وفقًا لـ Google، فإن coroutines في lifecycleScope هي الطريقة المفضلة لتنفيذ العمليات غير المتزامنة في onStop.

الأسئلة الشائعة

ما الفرق بين onStop و onDestroy؟

onStop — يتوقف النشاط عن الظهور لكنه يبقى في الذاكرة في الحالة Stopped. يمكن للنظام إعادة النشاط عبر onRestart. onDestroy — يتم تدمير النشاط وتحرير الذاكرة. بعد onDestroy، العودة ممكنة فقط عن طريق إنشاء مثيل جديد للنشاط (onCreate).

هل من الضروري استدعاء super.onStop()؟

نعم، إلزامي. يضمن super.onStop() التشغيل الصحيح لمكونات النظام: الأجزاء (fragments) و LoaderManager و ViewModelStore. تخطي super.onStop() قد يسبب تسربًا للذاكرة واستعادة غير صحيحة للأجزاء. استدعِ super.onStop() دائمًا في النهاية أو البداية — الترتيب ليس حرجًا، لكن الاستدعاء إلزامي.

كيف تتحقق من أن onStop تم استدعاؤه؟

استخدم Log.d أو Timber في كل طريقة من دورة الحياة. قم بتشغيل فلتر logcat بواسطة علامة النشاط الخاص بك. للإنتاج، استخدم Android Vitals — تقوم Google تلقائيًا بجمع مقاييس دورة الحياة وعرض الحالات الشاذة في Play Console. كما يتوفر مراقبة دورة الحياة عبر ProcessLifecycleOwner.

ماذا يحدث إذا تم طرح استثناء في onStop؟

الاستثناء غير الملتقط في onStop يسبب Force Close للتطبيق. النظام لا يلتقط الاستثناءات في استدعاءات دورة الحياة. إذا كانت onStop تنفذ عمليات قد تطرح استثناءً (عمليات الملفات، الشبكة)، قم بتغليفها في try-catch وسجل الخطأ دون مقاطعة super.onStop().

هل يجب تحرير Bitmap في onStop؟

لا، سيتم جمع Bitmap في النشاط بواسطة GC إذا لم تكن هناك مراجع له. التحرير القسري (recycle()) في onStop ليس ضروريًا بل قد يكون ضارًا — إذا عاد النشاط عبر onRestart، يجب تحميل Bitmap مرة أخرى. استخدم Glide أو Coil لتحميل الصور — هذه المكتبات تدير تلقائيًا التخزين المؤقت ودورة الحياة.

الملخص

  • onStop — طريقة دورة حياة النشاط التي يتم استدعاؤها عند فقدان الرؤية بالكامل. يبقى النشاط في الذاكرة في الحالة Stopped.
  • بعد onStop، هناك سيناريوهان محتملان: onRestart (العودة إلى الشاشة) أو onDestroy (تدمير النشاط).
  • في onStop، يجب تحرير أجهزة الاستشعار والرسوم المتحركة والكاميرا ومستمعي الموقع — كل ما لا يحتاجه النشاط عندما يكون غير مرئي.
  • يختلف onStop عن onPause في مستوى الرؤية: onPause — فقدان جزئي، onStop — فقدان كامل للرؤية.
  • يتم استدعاء onSaveInstanceState قبل onStop — استخدمه لحفظ حالة واجهة المستخدم العابرة.
  • Coroutines lifecycleScope مع Dispatchers.IO — الطريقة المفضلة للعمليات غير المتزامنة في onStop.
  • استدعِ دائمًا super.onStop() وقم بتغليف العمليات الخطرة في try-catch لتجنب Force Close.

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا