مراحل النشاط

بينما ينتقل المستخدم إلى تطبيقك وخارجه ثم يعود إليه، تنتقل حالات Activity في تطبيقك بحالات مختلفة خلال مراحل نشاطها. توفر الفئة Activity عددًا من استدعاءات الاستدعاء التي تتيح للنشاط معرفة متى تتغير حالة ما أو أن النظام ينشئ نشاطًا أو يوقفه أو يستأنفه أو يدمر العملية التي يتواجد فيها النشاط.

ضمن طرق معاودة الاتصال في مراحل النشاط، يمكنك توضيح سلوك نشاطك عندما يغادر المستخدم النشاط ويعيد الدخول إليه. على سبيل المثال، إذا كنت تنشئ مشغّلًا لبث الفيديو المباشر، يمكنك إيقاف الفيديو مؤقتًا وإنهاء اتصال الشبكة عندما ينتقل المستخدم إلى تطبيق آخر. وعندما يعود المستخدم، يمكنك إعادة الاتصال بالشبكة والسماح للمستخدم باستئناف تشغيل الفيديو من المكان نفسه.

تتيح لك كل معاودة اتصال أداء عمل محدد مناسب لتغيير حالة معين. يؤدي القيام بالعمل المناسب في الوقت المناسب والتعامل مع الانتقالات بشكل صحيح إلى جعل تطبيقك أكثر قوة وأداءً. على سبيل المثال، يمكن أن يساعد التنفيذ الجيد لاستدعاءات مراحل النشاط في تطبيقك تجنُّب ما يلي:

  • تعطّل التطبيق إذا تلقّى المستخدم مكالمة هاتفية أو انتقل إلى تطبيق آخر أثناء استخدام التطبيق
  • استهلاك موارد النظام القيّمة في حال عدم نشاط المستخدم فيها
  • فقدان مستوى تقدّم المستخدم في حال مغادرة التطبيق والعودة إليه في وقت لاحق.
  • تعطُّل مستوى تقدّم المستخدم أو فقدانه عند تدوير الشاشة بين الاتجاه الأفقي والعمودي

يشرح هذا المستند دورة حياة النشاط بالتفصيل. تبدأ الوثيقة بوصف نموذج دورة الحياة. بعد ذلك، يشرح كل من استدعاءات الاستدعاء: ما يحدث داخليًا أثناء تنفيذه وما تحتاج إلى تنفيذه أثناء تنفيذه.

ثم تقدم بإيجاز العلاقة بين حالة النشاط ومدى ثغرة العملية للقتل من قبل النظام. أخيرًا، يناقش العديد من الموضوعات المتعلقة بالانتقالات بين حالات النشاط.

للحصول على معلومات حول التعامل مع مراحل النشاط، بما في ذلك إرشادات حول أفضل الممارسات، راجِع معالجة مراحل النشاط باستخدام مكونات مستندة إلى مراحل النشاط وحفظ حالات واجهة المستخدم. لمعرفة كيفية تصميم تطبيق فعّال وعالي الجودة باستخدام أنشطة بالإضافة إلى مكونات البنية، يمكنك الاطّلاع على دليل بنية التطبيق.

مفاهيم مراحل نشاط النشاط

للتنقّل بين مراحل نشاط النشاط، توفّر الفئة Activity مجموعة أساسية من ستّ عمليات استدعاء: onCreate() وonStart() وonResume() وonPause() وonStop() وonDestroy(). يستدعي النظام كل من استدعاءات الاتصال هذه عندما يدخل النشاط في حالة جديدة.

يقدم الشكل 1 تمثيلاً مرئيًا لهذا النموذج.

الشكل 1. رسم توضيحي مبسط لدورة حياة النشاط.

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

في حال عاد المستخدم إلى النشاط، يستأنف من حيث توقّف المستخدم. مع بعض الاستثناءات، يتم منع التطبيقات من بدء الأنشطة عند تشغيلها في الخلفية.

تعتمد احتمالية قتل النظام لعملية معينة، إلى جانب الأنشطة التي تقوم بها، على حالة النشاط في ذلك الوقت. لمزيد من المعلومات حول العلاقة بين الحالة وثغرة إخراج الملفات، راجع القسم حول حالة النشاط والإخراج من الذاكرة.

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

عمليات معاودة الاتصال خلال مراحل النشاط

يقدم هذا القسم معلومات حول المفاهيم والتنفيذ حول طرق معاودة الاتصال المستخدمة خلال دورة حياة النشاط.

تنتمي بعض الإجراءات إلى طرق مراحل نشاط النشاط. ومع ذلك، ضع التعليمات البرمجية التي تنفذ إجراءات مكون تابع في المكون بدلاً من طريقة دورة حياة النشاط. لتحقيق ذلك، تحتاج إلى جعل المكونات التابعة مدركة لدورة حياة العناصر. لمعرفة كيفية جعل المكونات التابعة على دراية بمراحل نشاطها، يمكنك الاطّلاع على معالجة مراحل النشاط باستخدام مكونات مستندة إلى مراحل النشاط.

onCreate()

وعليك تنفيذ معاودة الاتصال هذه، والتي يتم تنشيطها عندما ينشئ النظام النشاط لأول مرة. عند إنشاء النشاط، يدخل النشاط في الحالة تاريخ الإنشاء. في الطريقة onCreate()، نفِّذ منطق بدء تشغيل التطبيق الأساسي الذي يحدث مرة واحدة فقط طوال عمر النشاط بالكامل.

على سبيل المثال، قد يؤدي تنفيذ onCreate() إلى ربط البيانات بالقوائم، وربط النشاط بـ ViewModel، وإنشاء مثيل لبعض متغيّرات نطاق الفئة. تتلقّى هذه الطريقة المعلَمة savedInstanceState، وهي كائن Bundle يحتوي على الحالة المحفوظة سابقًا للنشاط. وإذا لم يكن النشاط متوفرًا من قبل، تكون قيمة الكائن Bundle فارغة.

إذا كان لديك مكوِّن واعٍ بمراحل نشاطه ومرتبط بدورة حياة نشاطك، سيتلقّى حدث ON_CREATE. تُسمّى الطريقة التي تتضمّن تعليقات توضيحية باستخدام @OnLifecycleEvent لكي يتمكّن المكوِّن الواعي بدورة الحياة من تنفيذ أي رمز إعداد يحتاج إليه للحالة التي تم إنشاؤها.

ويوضّح المثال التالي لطريقة onCreate() الإعداد الأساسي للنشاط، مثل التعريف عن واجهة المستخدم (محدّدة في ملف تنسيق XML)، وتحديد متغيرات الأعضاء، وضبط بعض واجهة المستخدم. في هذا المثال، يمرّر ملف تنسيق XML معرّف مورد الملف R.layout.main_activity إلى setContentView().

Kotlin

lateinit var textView: TextView

// Some transient state for the activity instance.
var gameState: String? = null

override fun onCreate(savedInstanceState: Bundle?) {
    // Call the superclass onCreate to complete the creation of
    // the activity, like the view hierarchy.
    super.onCreate(savedInstanceState)

    // Recover the instance state.
    gameState = savedInstanceState?.getString(GAME_STATE_KEY)

    // Set the user interface layout for this activity.
    // The layout is defined in the project res/layout/main_activity.xml file.
    setContentView(R.layout.main_activity)

    // Initialize member TextView so it is available later.
    textView = findViewById(R.id.text_view)
}

// This callback is called only when there is a saved instance previously saved using
// onSaveInstanceState(). Some state is restored in onCreate(). Other state can optionally
// be restored here, possibly usable after onStart() has completed.
// The savedInstanceState Bundle is same as the one used in onCreate().
override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
    textView.text = savedInstanceState?.getString(TEXT_VIEW_KEY)
}

// Invoked when the activity might be temporarily destroyed; save the instance state here.
override fun onSaveInstanceState(outState: Bundle?) {
    outState?.run {
        putString(GAME_STATE_KEY, gameState)
        putString(TEXT_VIEW_KEY, textView.text.toString())
    }
    // Call superclass to save any view hierarchy.
    super.onSaveInstanceState(outState)
}

Java

TextView textView;

// Some transient state for the activity instance.
String gameState;

@Override
public void onCreate(Bundle savedInstanceState) {
    // Call the superclass onCreate to complete the creation of
    // the activity, like the view hierarchy.
    super.onCreate(savedInstanceState);

    // Recover the instance state.
    if (savedInstanceState != null) {
        gameState = savedInstanceState.getString(GAME_STATE_KEY);
    }

    // Set the user interface layout for this activity.
    // The layout is defined in the project res/layout/main_activity.xml file.
    setContentView(R.layout.main_activity);

    // Initialize member TextView so it is available later.
    textView = (TextView) findViewById(R.id.text_view);
}

// This callback is called only when there is a saved instance previously saved using
// onSaveInstanceState(). Some state is restored in onCreate(). Other state can optionally
// be restored here, possibly usable after onStart() has completed.
// The savedInstanceState Bundle is same as the one used in onCreate().
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
    textView.setText(savedInstanceState.getString(TEXT_VIEW_KEY));
}

// Invoked when the activity might be temporarily destroyed; save the instance state here.
@Override
public void onSaveInstanceState(Bundle outState) {
    outState.putString(GAME_STATE_KEY, gameState);
    outState.putString(TEXT_VIEW_KEY, textView.getText());

    // Call superclass to save any view hierarchy.
    super.onSaveInstanceState(outState);
}

كبديل لتحديد ملف XML وتمريره إلى setContentView()، يمكنك إنشاء عناصر View جديدة في رمز النشاط وإنشاء تسلسل هرمي لطريقة العرض من خلال إدراج عناصر View جديدة في ViewGroup. يمكنك بعد ذلك استخدام هذا التنسيق من خلال تمرير الجذر ViewGroup إلى setContentView(). للاطّلاع على مزيد من المعلومات عن إنشاء واجهة مستخدم، يمكنك مراجعة مستندات واجهة المستخدم.

لن يظل نشاطك في حالة الإنشاء. بعد انتهاء تنفيذ الطريقة onCreate()، يدخل النشاط في الحالة Started ويطلب النظام طريقتَي onStart() وonResume() بنجاح سريع.

onStart()

عندما يدخل النشاط في حالة "تم البدء"، يستدعي النظام onStart(). تجعل هذه المكالمة النشاط مرئيًا للمستخدم بينما يستعد التطبيق للنشاط للدخول في المقدمة ويصبح تفاعليًا. على سبيل المثال، هذه الطريقة هي المكان الذي يتم فيه تهيئة التعليمة البرمجية التي تحافظ على واجهة المستخدم.

عندما ينتقل النشاط إلى حالة "تم البدء"، يتلقّى أي مكوِّن واعٍ لمراحل نشاط ومرتبط بدورة حياة النشاط حدث ON_START.

تكتمل طريقة onStart() بسرعة، وكما هي الحال في حالة "إنشاء"، لا يظل النشاط بحالة "تم البدء". بعد انتهاء معاودة الاتصال هذه، يدخل النشاط في الحالة مستأنف ويستدعي النظام الطريقة onResume().

onCV()

وعندما يدخل النشاط في حالة استئنافه، يظهر في المقدّمة ويستدعي النظام معاودة الاتصال بـ "onResume()". هذه هي الحالة التي يتفاعل فيها التطبيق مع المستخدم. يظل التطبيق في هذه الحالة إلى أن يحدث شيء ما لتغيير التركيز عن التطبيق، مثل استقبال الجهاز مكالمة هاتفية أو انتقال المستخدم إلى نشاط آخر أو إيقاف شاشة الجهاز.

عند انتقال النشاط إلى الحالة "مستأنف"، يتلقى أي مكوِّن واعٍ لمراحل نشاط ومرتبط بدورة حياة النشاط حدث ON_RESUME. هذا هو المكان الذي يمكن فيه لمكونات دورة الحياة تفعيل أي وظيفة تحتاج إلى تشغيلها عندما يكون المكوِّن مرئيًا وفي المقدّمة، مثل بدء معاينة الكاميرا.

عند وقوع حدث قاطع، يدخل النشاط في الحالة متوقف مؤقتًا ويستدعي النظام onPause() معاودة الاتصال.

في حال عاد النشاط إلى الحالة "مستأنف" من حالة "متوقف مؤقتًا"، يستدعي النظام طريقة onResume() مرة أخرى. ولهذا السبب، نفِّذ onResume() لإعداد المكوّنات التي يتم إصدارها خلال onPause() ولتنفيذ أي عمليات إعداد أخرى يجب أن تحدث في كل مرة يدخل فيها النشاط إلى حالة الاستئناف.

في ما يلي مثال لمكوِّن واعٍ لمراحل نشاطه يدخل إلى الكاميرا عندما يتلقّى المكوِّن حدث ON_RESUME:

Kotlin

class CameraComponent : LifecycleObserver {
    ...
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    fun initializeCamera() {
        if (camera == null) {
            getCamera()
        }
    }
    ...
}

Java

public class CameraComponent implements LifecycleObserver {

    ...

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    public void initializeCamera() {
        if (camera == null) {
            getCamera();
        }
    }
    ...
}

يؤدي الرمز السابق إلى إعداد الكاميرا بعد تلقّي LifecycleObserver حدث ON_RESUME. ومع ذلك، في وضع النوافذ المتعددة، قد يكون نشاطك مرئيًا بالكامل حتى عندما يكون في حالة الإيقاف المؤقت. على سبيل المثال، عندما يكون التطبيق في وضع النوافذ المتعددة وينقر المستخدم على النافذة التي لا تحتوي على نشاطك، ينتقل نشاطك إلى حالة الإيقاف المؤقت.

إذا كنت تريد تفعيل الكاميرا عند استئناف التطبيق فقط (مرئي ونشط في المقدّمة)، عليك إعداد الكاميرا بعد حدث ON_RESUME الذي تم توضيحه سابقًا. إذا أردت إبقاء الكاميرا نشطة أثناء إيقاف النشاط متوقفًا مؤقتًا ومرئيًا كما هو الحال في وضع النوافذ المتعددة، عليك ضبط إعدادات الكاميرا بعد حدث "ON_START".

ومع ذلك، قد يؤدي تفعيل الكاميرا أثناء إيقاف نشاطك مؤقتًا إلى رفض الوصول إلى الكاميرا من تطبيق آخر تم استئنافه في وضع النوافذ المتعددة. في بعض الأحيان، من الضروري الحفاظ على نشاط الكاميرا أثناء إيقاف نشاطك مؤقتًا، ولكن في الواقع قد يؤدي ذلك إلى انخفاض مستوى تجربة المستخدم بشكل عام إذا فعلت ذلك.

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

بغض النظر عن حدث الإنشاء الذي تختاره لتنفيذ عملية إعداد، تأكَّد من استخدام حدث مراحل النشاط المقابل لتحرير المورد. في حال إعداد عنصر بعد حدث ON_START، عليك إطلاقه أو إنهاؤه بعد حدث ON_STOP. إذا تم الانتهاء من الإعداد بعد حدث ON_RESUME، أفلِته بعد الحدث ON_PAUSE.

يضع مقتطف الرمز السابق رمز إعداد الكاميرا في مكوِّن مدرك لمراحل النشاط. يمكنك بدلاً من ذلك وضع هذا الرمز مباشرةً في عمليات استدعاء مرحلة نشاط النشاط، مثل onStart() وonStop()، لكننا لا ننصح بذلك. تتيح لك إضافة هذا المنطق إلى مكون مستقل وواعي لدورة الحياة إعادة استخدام المكون عبر أنشطة متعددة دون الحاجة إلى تكرار التعليمات البرمجية. لمعرفة كيفية إنشاء مكوِّن واعٍ لمراحل النشاط، يُرجى الاطّلاع على معالجة مراحل النشاط باستخدام مكونات الوعي بدورة الحياة.

onPause()

يُطلق النظام على هذه الطريقة إشارة أول إلى أن المستخدم يغادر النشاط، على الرغم من أنه لا يعني دائمًا أنه يتم إتلاف النشاط. يشير هذا إلى أنّ النشاط لم يعُد في المقدّمة، ولكنه لا يزال مرئيًا إذا كان المستخدم في وضع النوافذ المتعددة. هناك عدة أسباب وراء دخول النشاط إلى هذه الحالة:

  • إنّ الحدث الذي يقاطع تنفيذ التطبيق، كما هو موضّح في القسم المتعلّق بمعاودة الاتصال onاستئناف()، يؤدي إلى إيقاف النشاط الحالي مؤقتًا. وهذه الحالة هي الأكثر شيوعًا.
  • في وضع النوافذ المتعددة، يتم التركيز على تطبيق واحد فقط في أي وقت ويوقف النظام جميع التطبيقات الأخرى مؤقتًا.
  • تؤدي بداية نشاط جديد شبه شفاف، مثل مربّع الحوار، إلى إيقاف النشاط الذي يتناوله مؤقتًا. وسيظل النشاط مرئيًا جزئيًا ولكن ليس محلّ التركيز، وسيبقى متوقفًا مؤقتًا.

عند انتقال نشاط إلى حالة "متوقف مؤقتًا"، يتلقى أي مكوِّن واعٍ لمراحل نشاط ومرتبط بدورة حياة النشاط حدث ON_PAUSE. هذا هو المكان الذي يمكن أن تؤدي فيه مكوّنات دورة الحياة إلى إيقاف أي وظائف لا يلزم تشغيلها عندما لا يكون المكوِّن في المقدمة، مثل إيقاف معاينة الكاميرا.

استخدِم طريقة onPause() لإيقاف أو ضبط العمليات التي لا يمكن أن تستمر أو قد تستمر في الإشراف، عندما تكون "Activity" في حالة "متوقّفة مؤقّتًا" والتي من المتوقّع أن يتم استئنافها بعد فترة قصيرة.

يمكنك أيضًا استخدام طريقة onPause() لتحرير موارد النظام، أو استخدام أدوات الاستشعار (مثل نظام تحديد المواقع العالمي (GPS)) أو أي موارد تؤثر في عمر البطارية عندما يكون نشاطك متوقّفًا مؤقتًا ولا يحتاج المستخدم إليها.

ومع ذلك، كما هو مذكور في القسم حول onResume()، قد يظل النشاط المتوقف مؤقتًا مرئيًا بشكل كامل إذا كان التطبيق في وضع النوافذ المتعددة. يمكنك استخدام onStop() بدلاً من onPause() لإصدار الموارد والعمليات المتعلقة بواجهة المستخدم أو تعديلها بالكامل من أجل توفير وضع النوافذ المتعددة بشكل أفضل.

المثال التالي لتفاعل LifecycleObserver مع حدث ON_PAUSE هو نظير مثال حدث ON_RESUME السابق، حيث يتم إطلاق الكاميرا التي يتم إعدادها بعد تلقّي حدث ON_RESUME:

Kotlin

class CameraComponent : LifecycleObserver {
    ...
    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    fun releaseCamera() {
        camera?.release()
        camera = null
    }
    ...
}

Java

public class JavaCameraComponent implements LifecycleObserver {
    ...
    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    public void releaseCamera() {
        if (camera != null) {
            camera.release();
            camera = null;
        }
    }
    ...
}

يضع هذا المثال رمز إطلاق الكاميرا بعد استلام الحدث ON_PAUSE من قِبل LifecycleObserver.

عملية تنفيذ onPause() قصيرة للغاية ولا توفّر بالضرورة وقتًا كافيًا لإجراء عمليات الحفظ. لهذا السبب، لا تستخدم onPause() لحفظ بيانات التطبيقات أو المستخدمين أو إجراء مكالمات الشبكة أو تنفيذ معاملات قاعدة البيانات. قد لا يكتمل هذا العمل قبل اكتمال الطريقة.

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

لا يعني إكمال طريقة onPause() أن النشاط يترك حالة "الإيقاف المؤقت". وبدلاً من ذلك، يظل النشاط في هذه الحالة حتى يتم استئناف النشاط أو يصبح غير مرئي تمامًا للمستخدم. وفي حال استئناف النشاط، يستدعي النظام مرة أخرى استدعاء onResume().

وإذا عاد النشاط من حالة "الإيقاف المؤقت" إلى حالة الاستئناف، يبقي النظام المثيل Activity مثبّتًا في الذاكرة، مع تذكُّر ذلك المثيل عندما يستدعي النظام onResume(). في هذا السيناريو، لن تحتاج إلى إعادة تهيئة المكونات التي تم إنشاؤها أثناء أي من طرق معاودة الاتصال التي تؤدي إلى الحالة الاستئنافية. إذا أصبح النشاط غير مرئي تمامًا، يستدعي النظام onStop().

onStop()

عندما لا يعود نشاطك مرئيًا للمستخدم، يدخل الحالة متوقّف ويستدعي النظام onStop(). ويمكن أن يحدث ذلك عندما يغطي نشاط تم إطلاقه حديثًا الشاشة بأكملها. يستدعي النظام أيضًا onStop() عندما ينتهي النشاط ويوشك على الانتهاء.

عندما ينتقل النشاط إلى حالة "متوقّف"، يتلقّى أي مكوِّن ومرتبط بدورة حياة النشاط حدث ON_STOP. هذا هو المكان الذي يمكن فيه لمكونات دورة الحياة إيقاف أي وظائف لا يلزم تشغيلها عندما يكون المكون غير مرئي على الشاشة.

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

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

Kotlin

override fun onStop() {
    // Call the superclass method first.
    super.onStop()

    // Save the note's current draft, because the activity is stopping
    // and we want to be sure the current note progress isn't lost.
    val values = ContentValues().apply {
        put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText())
        put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle())
    }

    // Do this update in background on an AsyncQueryHandler or equivalent.
    asyncQueryHandler.startUpdate(
            token,     // int token to correlate calls
            null,      // cookie, not used here
            uri,       // The URI for the note to update.
            values,    // The map of column names and new values to apply to them.
            null,      // No SELECT criteria are used.
            null       // No WHERE columns are used.
    )
}

Java

@Override
protected void onStop() {
    // Call the superclass method first.
    super.onStop();

    // Save the note's current draft, because the activity is stopping
    // and we want to be sure the current note progress isn't lost.
    ContentValues values = new ContentValues();
    values.put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText());
    values.put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle());

    // Do this update in background on an AsyncQueryHandler or equivalent.
    asyncQueryHandler.startUpdate (
            mToken,  // int token to correlate calls
            null,    // cookie, not used here
            uri,    // The URI for the note to update.
            values,  // The map of column names and new values to apply to them.
            null,    // No SELECT criteria are used.
            null     // No WHERE columns are used.
    );
}

يستخدم عينة التعليمات البرمجية السابقة لغة SQLite مباشرةً. ومع ذلك، نوصي باستخدام Room، وهي مكتبة مثابرة توفر طبقة تجريد عبر SQLite. للاطّلاع على مزيد من المعلومات حول مزايا استخدام الغرفة وكيفية استخدام الغرفة في تطبيقك، راجِع دليل مكتبة استمرارية الغرفة.

عندما يدخل نشاطك في حالة الإيقاف، يبقى الكائن Activity مثبّتًا في الذاكرة: يحتفظ بجميع معلومات الحالة والأعضاء، لكن لا يتم إرفاقه بمدير النوافذ. عند استئناف النشاط، يتذكر هذه المعلومات.

لن تحتاج إلى إعادة تهيئة المكونات التي تم إنشاؤها أثناء أي من طرق معاودة الاتصال التي أدت إلى حالة الاستئناف. يتتبّع النظام أيضًا الحالة الحالية لكل عنصر View في التنسيق، وبالتالي إذا أدخل المستخدم نصًا في أداة EditText، سيتم الاحتفاظ بهذا المحتوى كي لا تحتاج إلى حفظه واستعادته.

ملاحظة: بعد إيقاف نشاطك، قد يمحو النظام العملية التي تحتوي على النشاط إذا احتاج النظام إلى استرداد الذاكرة. حتى إذا أتلف النظام العملية أثناء إيقاف النشاط، سيحتفظ النظام بحالة عناصر View، مثل النص في الأداة EditText، في Bundle، وهو عبارة عن كائن ثنائي كبير من أزواج المفتاح/القيمة، واستعادته في حال عاد المستخدم إلى النشاط. لمزيد من المعلومات حول استعادة نشاط يعود إليه المستخدم، يمكنك الاطّلاع على القسم حول حفظ الحالة واستعادتها.

من الحالة "متوقف"، إما أن يعود النشاط للتفاعل مع المستخدم أو أن النشاط قد ينتهي تشغيله ويتوقف عن ذلك. وإذا عاد النشاط، يستدعي النظام onRestart(). إذا اكتملت عملية "Activity" في التشغيل، سيستدعي النظام onDestroy().

onDestroy()

يتم استدعاء onDestroy() قبل تدمير النشاط. يستدعي النظام معاودة الاتصال هذه لأحد السببَين التاليَين:

  1. يكتمل النشاط لأنّ المستخدم يرفض النشاط تمامًا أو بسبب طلب finish() إلى النشاط.
  2. يمحو النظام النشاط مؤقتًا بسبب تغيير في الإعدادات، مثل تدوير الجهاز أو الدخول في وضع النوافذ المتعددة.

عندما ينتقل النشاط إلى الحالة التي تم محوها، يتلقى أي مكوِّن واعٍ لمراحل نشاط ومرتبط بدورة حياة النشاط حدث ON_DESTROY. هذا هو المكان الذي يمكن فيه لمكوّنات مراحل النشاط تنظيف أي شيء يحتاجون إليه قبل تدمير Activity.

بدلاً من استخدام المنطق في Activity لتحديد سبب تدميره، استخدِم عنصر ViewModel لتضمين بيانات الملف الشخصي ذات الصلة بـ Activity. وإذا تمت إعادة إنشاء Activity بسبب تغيير في الإعدادات، لن يكون على ViewModel اتخاذ أي إجراء، لأنّه يتم الاحتفاظ بها وتقديمها لمثيل Activity التالي.

إذا لم تتم إعادة إنشاء Activity، يتم استدعاء طريقة ViewModel باستخدام طريقة onCleared()، حيث يمكنها حذف أي بيانات تحتاج إليها قبل إتلافها. ويمكنك التمييز بين هذين السيناريوهَين باستخدام طريقة isFinishing().

في حال انتهاء النشاط، تكون onDestroy() هي معاودة الاتصال بدورة الحياة النهائية التي يتلقّاها النشاط. إذا تم استدعاء onDestroy() نتيجة لتغيير في الإعدادات، ينشئ النظام على الفور مثيل نشاط جديدًا ثم يستدعي onCreate() على ذلك المثيل الجديد في الإعدادات الجديدة.

يؤدي استدعاء onDestroy() إلى إطلاق جميع الموارد التي لم تتم إزالتها في عمليات معاودة الاتصال السابقة، مثل onStop().

حالة النشاط والإخراج من الذاكرة

يوقف النظام العمليات عند الحاجة إلى إخلاء مساحة من ذاكرة الوصول العشوائي (RAM). وتعتمد احتمالية إيقاف النظام لعملية معينة على حالة العملية في ذلك الوقت. تعتمد حالة العملية، بدورها، على حالة النشاط الجاري في العملية. يوضح الجدول 1 الارتباطات بين حالة العملية، وحالة النشاط، واحتمالية قيام النظام بإنهاء العملية. لا ينطبق هذا الجدول إلا إذا كانت العملية لا تستخدم أنواعًا أخرى من مكوّنات التطبيق.

احتمالية القتل حالة العملية حالة النشاط النهائي
المدى الأقل للخطورة في المقدّمة (بعد التركيز أو على وشك التركيز) تم استئناف العملية
جمهور صغير مرئية (بدون تركيز) تم بدء التنفيذ/إيقافه مؤقتًا
جودة أعلى الخلفية (غير مرئية) الجهاز متوقّف
المبلغ الأعلى ما مِن لاعبين تم إزالتها

الجدول 1. العلاقة بين دورة حياة العملية وحالة النشاط.

لا يوقف النظام أي نشاط مباشرةً لإخلاء مساحة من الذاكرة. بدلاً من ذلك، فإنه يقتل العملية التي يجري فيها النشاط، ويدمّر ليس فقط النشاط بل يدمر كل شيء آخر يجري في العملية أيضًا. لمعرفة كيفية الحفاظ على حالة واجهة مستخدم النشاط واستعادتها عند حدوث وفاة للعمليات التي يجريها النظام، راجع القسم حول حفظ الحالة واستعادتها.

يمكن للمستخدم أيضًا إنهاء إحدى العمليات باستخدام مدير التطبيقات، ضمن الإعدادات، لإنهاء التطبيق المقابل.

لمزيد من المعلومات حول العمليات، يُرجى الاطّلاع على نظرة عامة على العمليات وسلاسل المحادثات.

حفظ واستعادة حالة واجهة المستخدم المؤقتة

يتوقّع المستخدم أن تظل حالة واجهة مستخدم النشاط كما هي خلال تغيير في الإعدادات، مثل التدوير أو التبديل إلى وضع النوافذ المتعددة. ومع ذلك، يدمر النظام النشاط تلقائيًا عند حدوث هذا التغيير في الإعدادات، ما يمحو أي حالة لواجهة مستخدم مخزَّنة في مثيل النشاط.

وبالمثل، يتوقع المستخدم أن تظل حالة واجهة المستخدم كما هي إذا انتقل بعيدًا مؤقتًا من تطبيقك إلى تطبيق مختلف ثم عاد إلى التطبيق لاحقًا. ومع ذلك، يمكن للنظام إتلاف عملية تطبيقك أثناء غياب المستخدم وإيقاف نشاطك.

عندما تتسبّب قيود النظام في تدمير النشاط، يمكنك الحفاظ على الحالة المؤقتة لواجهة المستخدم من خلال مجموعة من ViewModel و/أو onSaveInstanceState() و/أو مساحة التخزين على الجهاز. لمعرفة المزيد من المعلومات حول توقعات المستخدم مقارنةً بسلوك النظام وكيفية الاحتفاظ بأفضل شكل لبيانات حالة واجهة المستخدم المعقدة عبر النشاط الذي يبدأه النظام وإنهاء العملية، يُرجى الاطّلاع على حفظ حالات واجهة المستخدم.

يوضّح هذا القسم حالة المثيل وكيفية تنفيذ طريقة onSaveInstance()، وهي استدعاء في النشاط نفسه. إذا كانت بيانات واجهة المستخدم بسيطة، يمكنك استخدام onSaveInstance() فقط للاحتفاظ بحالة واجهة المستخدم في كل من تغييرات الإعدادات وإنهاء العمليات التي يبدأها النظام. بما أنّ السمة onSaveInstance() تتحمّل تكاليف تسلسل/إلغاء الترتيب، فإنّك تستخدم في معظم الحالات ViewModel وonSaveInstance()، كما هو موضّح في حفظ حالات واجهة المستخدم.

ملاحظة: لمزيد من المعلومات حول التغييرات على الإعدادات، وكيفية فرض قيود على تنفيذ التغييرات في الإعدادات إذا لزم الأمر، وكيفية التفاعل مع تغييرات الإعدادات هذه من نظام العرض وJetpack Compose، اطّلِع على صفحة التعامل مع تغييرات الإعدادات.

حالة المثيل

هناك بعض السيناريوهات التي يتم فيها إتلاف نشاطك بسبب السلوك الطبيعي للتطبيق، مثلاً عندما يضغط المستخدم على زر الرجوع أو يشير نشاطك إلى تدميره بنفسه من خلال استدعاء الطريقة finish().

عندما يتم إتلاف نشاطك لأنّ المستخدم يضغط على زر الرجوع أو ينتهي النشاط من تلقاء نفسه، يختفي كل من مفهوم Activity للنظام والمستخدم إلى الأبد. في هذه السيناريوهات، يتطابق توقع المستخدم مع سلوك النظام، وليس لديك أي عمل إضافي للقيام به.

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

وتُسمى البيانات المحفوظة التي يستخدمها النظام لاستعادة الحالة السابقة حالة المثيل. وهي مجموعة من أزواج المفتاح/القيمة المخزنة في كائن Bundle. يستخدم النظام تلقائيًا حالة المثيل Bundle لحفظ المعلومات عن كل عنصر View في تنسيق نشاطك، مثل قيمة النص التي تم إدخالها في تطبيق EditText المصغّر.

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

ملاحظة: ليتمكّن نظام Android من استعادة حالة المشاهدات في نشاطك، يجب أن يكون لكل ملف شخصي معرّف فريد يتم توفيره من خلال السمة android:id.

لا يصلح كائن Bundle لحفظ أكثر من كمية تافهة من البيانات، لأنّه يتطلّب إنشاء تسلسل على سلسلة التعليمات الرئيسية ويستهلك ذاكرة عمليات النظام. للحفاظ على كمية أكبر من كمية صغيرة جدًا من البيانات، اتّبِع نهجًا مجمّعًا للاحتفاظ بالبيانات باستخدام مساحة تخزين محلية دائمة وطريقة onSaveInstanceState() وفئة ViewModel، كما هو موضّح في حفظ حالات واجهة المستخدم.

حفظ حالة واجهة المستخدم البسيطة والخفيفة باستخدام onSaveInstanceState()

عند بدء إيقاف نشاطك، يستدعي النظام الطريقة onSaveInstanceState() ليتمكّن نشاطك من حفظ معلومات الحالة في حزمة حالة للمثيل. يحفظ التنفيذ التلقائي لهذه الطريقة معلومات مؤقتة عن حالة العرض الهرمي للنشاط، مثل النص في تطبيق EditText المصغّر أو موضع التمرير في تطبيق ListView المصغّر.

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

Kotlin

override fun onSaveInstanceState(outState: Bundle?) {
    // Save the user's current game state.
    outState?.run {
        putInt(STATE_SCORE, currentScore)
        putInt(STATE_LEVEL, currentLevel)
    }

    // Always call the superclass so it can save the view hierarchy state.
    super.onSaveInstanceState(outState)
}

companion object {
    val STATE_SCORE = "playerScore"
    val STATE_LEVEL = "playerLevel"
}

Java

static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
// ...


@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    // Save the user's current game state.
    savedInstanceState.putInt(STATE_SCORE, currentScore);
    savedInstanceState.putInt(STATE_LEVEL, currentLevel);

    // Always call the superclass so it can save the view hierarchy state.
    super.onSaveInstanceState(savedInstanceState);
}

ملاحظة: لا يتم استدعاء onSaveInstanceState() عندما يغلق المستخدم النشاط بشكل صريح أو في حالات أخرى عند استدعاء finish().

لحفظ البيانات الدائمة، مثل الإعدادات المفضّلة للمستخدم أو البيانات لقاعدة بيانات، يمكنك الاستفادة من الفرص المناسبة عندما يكون نشاطك في المقدمة. وإذا لم تظهر هذه الفرصة، يمكنك حفظ البيانات المستمرة أثناء استخدام طريقة onStop().

استعادة حالة واجهة مستخدم النشاط باستخدام حالة المثيل المحفوظ

عند إعادة إنشاء نشاطك بعد تلفه سابقًا، يمكنك استعادة حالة المثيل المحفوظة من Bundle التي يمرّرها النظام إلى نشاطك. تتلقّى كل من طريقتَي معاودة الاتصال onCreate() و onRestoreInstanceState() القيمة ذاتها Bundle التي تحتوي على معلومات حالة المثيل.

بما أنّ طريقة onCreate() تستدعي ما إذا كان النظام ينشئ مثيلاً جديدًا لنشاطك أو يعيد إنشاء مثيل سابق، عليك التحقق مما إذا كانت الحالة Bundle فارغة قبل أن تحاول قراءتها. وإذا كانت فارغة، فإن النظام يقوم بإنشاء مثيل جديد من النشاط، بدلاً من استعادة مثيل سابق تم تلفه.

يعرض مقتطف الرمز التالي كيفية استعادة بعض بيانات الحالة في onCreate():

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState) // Always call the superclass first

    // Check whether we're recreating a previously destroyed instance.
    if (savedInstanceState != null) {
        with(savedInstanceState) {
            // Restore value of members from saved state.
            currentScore = getInt(STATE_SCORE)
            currentLevel = getInt(STATE_LEVEL)
        }
    } else {
        // Probably initialize members with default values for a new instance.
    }
    // ...
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); // Always call the superclass first

    // Check whether we're recreating a previously destroyed instance.
    if (savedInstanceState != null) {
        // Restore value of members from saved state.
        currentScore = savedInstanceState.getInt(STATE_SCORE);
        currentLevel = savedInstanceState.getInt(STATE_LEVEL);
    } else {
        // Probably initialize members with default values for a new instance.
    }
    // ...
}

بدلاً من استعادة الحالة أثناء onCreate()، يمكنك اختيار تطبيق onRestoreInstanceState()، التي يستدعيها النظام بعد طريقة onStart(). يستدعي النظام onRestoreInstanceState() فقط في حال وجود حالة محفوظة لاستعادتها، لذلك لن تحتاج إلى التحقّق مما إذا كانت قيمة Bundle فارغة.

Kotlin

override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
    // Always call the superclass so it can restore the view hierarchy.
    super.onRestoreInstanceState(savedInstanceState)

    // Restore state members from saved instance.
    savedInstanceState?.run {
        currentScore = getInt(STATE_SCORE)
        currentLevel = getInt(STATE_LEVEL)
    }
}

Java

public void onRestoreInstanceState(Bundle savedInstanceState) {
    // Always call the superclass so it can restore the view hierarchy.
    super.onRestoreInstanceState(savedInstanceState);

    // Restore state members from saved instance.
    currentScore = savedInstanceState.getInt(STATE_SCORE);
    currentLevel = savedInstanceState.getInt(STATE_LEVEL);
}

تنبيه: يجب دائمًا طلب تنفيذ الفئة الرئيسية للسمة onRestoreInstanceState() حتى يستعيد التطبيق التلقائي حالة العرض الهرمي لطريقة العرض.

التنقّل بين الأنشطة

من المحتمل أن يدخل التطبيق إلى نشاط ويخرج منه، ربما عدة مرات خلال فترة استخدام التطبيق، مثل النقر على زر الرجوع في الجهاز أو عند بدء النشاط لنشاط مختلف.

يتناول هذا القسم الموضوعات التي تحتاج إلى معرفتها لتنفيذ عمليات انتقال ناجحة بين الأنشطة. تتضمن هذه الموضوعات بدء نشاط من نشاط آخر، وحفظ حالة النشاط، واستعادة حالة النشاط.

بدء نشاط من آخر

غالبًا ما يحتاج النشاط إلى بدء نشاط آخر في مرحلة ما. تظهر هذه الحاجة، على سبيل المثال، عندما يحتاج تطبيق إلى الانتقال من الشاشة الحالية إلى شاشة جديدة.

اعتمادًا على ما إذا كان نشاطك يريد الحصول على نتيجة من النشاط الجديد على وشك بدئه، تبدأ النشاط الجديد باستخدام إما طريقة startActivity() أو طريقة startActivityForResult(). وفي كلتا الحالتين، يتم إدخال كائن Intent.

يحدد الكائن Intent إما النشاط الذي تريد بدؤه بالضبط أو يصف نوع الإجراء الذي تريد تنفيذه. يختار النظام النشاط المناسب لك، والذي يمكن أن يكون من تطبيق مختلف. ويمكن أيضًا أن يحمل كائن Intent كميات صغيرة من البيانات لاستخدامها في النشاط الذي بدأه. لمزيد من المعلومات عن الفئة Intent، يُرجى الاطّلاع على فلاتر Intent وIntent.

startActivity()

إذا لم يكن النشاط الذي تم بدؤه حديثًا بحاجة إلى عرض نتيجة، يمكن أن يبدأ النشاط الحالي من خلال استدعاء الطريقة startActivity().

عند العمل داخل تطبيقك الخاص، ستحتاج غالبًا إلى بدء نشاط معروف ببساطة. على سبيل المثال، يعرض مقتطف الرمز التالي كيفية بدء نشاط يُسمى SignInActivity.

Kotlin

val intent = Intent(this, SignInActivity::class.java)
startActivity(intent)

Java

Intent intent = new Intent(this, SignInActivity.class);
startActivity(intent);

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

هذا هو المكان الذي تكون فيه النوايا ذات قيمة حقًا. يمكنك إنشاء هدف يصف الإجراء الذي تريد تنفيذه، ويطلق النظام النشاط المناسب من تطبيق آخر. وإذا كانت هناك أنشطة متعددة يمكنها التعامل مع الغرض، فيمكن للمستخدم اختيار النشاط الذي سيستخدمه. على سبيل المثال، إذا كنت تريد السماح للمستخدم بإرسال رسالة بريد إلكتروني، يمكنك إنشاء الغرض التالي:

Kotlin

val intent = Intent(Intent.ACTION_SEND).apply {
    putExtra(Intent.EXTRA_EMAIL, recipientArray)
}
startActivity(intent)

Java

Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity(intent);

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

startActivityForResult()

قد تريد أحيانًا الحصول على نتيجة من نشاط عند انتهائه. على سبيل المثال، قد تبدأ نشاطًا يتيح للمستخدم اختيار شخص من قائمة جهات الاتصال. عند انتهاء ذلك، يتم عرض الشخص الذي تم اختياره. لإجراء ذلك، عليك استدعاء الطريقة startActivityForResult(Intent, int) حيث تحدِّد مَعلمة العدد الصحيح المكالمة.

يهدف هذا المعرّف إلى التمييز بين الطلبات المتعدّدة التي ترِد إلى startActivityForResult(Intent, int) من النشاط نفسه. وهو ليس معرّفًا عموميًا ولا يتعرض لخطر التعارض مع التطبيقات أو الأنشطة الأخرى. تأتي النتيجة من خلال طريقة onActivityResult(int, int, Intent) الخاصة بك.

عند الخروج من نشاط فرعي، يمكنه استدعاء الدالة setResult(int) لعرض البيانات إلى نشاطه الرئيسي. يجب أن يوفّر النشاط الفرعي رمز نتيجة قد يكون النتائج العادية RESULT_CANCELED أو RESULT_OK أو أي قيم مخصّصة تبدأ بـ RESULT_FIRST_USER.

بالإضافة إلى ذلك، يمكن أن يعرض النشاط الفرعي بشكل اختياري كائن Intent يحتوي على أي بيانات إضافية يريدها. يستخدم النشاط الرئيسي طريقة onActivityResult(int, int, Intent) مع معرّف العدد الصحيح الذي وفّره النشاط الرئيسي في الأصل لتلقّي المعلومات.

إذا تعذَّر تنفيذ نشاط فرعي لأي سبب من الأسباب، مثل تعطُّله، سيتلقّى النشاط الرئيسي نتيجة تتضمّن الرمز RESULT_CANCELED.

Kotlin

class MyActivity : Activity() {
    // ...

    override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
        if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
            // When the user center presses, let them pick a contact.
            startActivityForResult(
                    Intent(Intent.ACTION_PICK,Uri.parse("content://contacts")),
                    PICK_CONTACT_REQUEST)
            return true
        }
        return false
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
        when (requestCode) {
            PICK_CONTACT_REQUEST ->
                if (resultCode == RESULT_OK) {
                    // A contact was picked. Display it to the user.
                    startActivity(Intent(Intent.ACTION_VIEW, intent?.data))
                }
        }
    }

    companion object {
        internal val PICK_CONTACT_REQUEST = 0
    }
}

Java

public class MyActivity extends Activity {
     // ...

     static final int PICK_CONTACT_REQUEST = 0;

     public boolean onKeyDown(int keyCode, KeyEvent event) {
         if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
             // When the user center presses, let them pick a contact.
             startActivityForResult(
                 new Intent(Intent.ACTION_PICK,
                 new Uri("content://contacts")),
                 PICK_CONTACT_REQUEST);
            return true;
         }
         return false;
     }

     protected void onActivityResult(int requestCode, int resultCode,
             Intent data) {
         if (requestCode == PICK_CONTACT_REQUEST) {
             if (resultCode == RESULT_OK) {
                 // A contact was picked. Display it to the user.
                 startActivity(new Intent(Intent.ACTION_VIEW, data));
             }
         }
     }
 }

تنسيق الأنشطة

عندما يبدأ أحد الأنشطة في نشاط آخر، يواجه كلاهما انتقالات مراحل النشاط. يتوقف النشاط الأول عن العمل ويدخل في حالة "متوقف مؤقتًا" أو "متوقف"، بينما يتم إنشاء النشاط الآخر. وفي حالة مشاركة هذه الأنشطة للبيانات المحفوظة على قرص أو في أي مكان آخر، من المهم أن تفهم أن النشاط الأول لا يتوقف تمامًا قبل إنشاء النشاط الثاني. وبدلاً من ذلك، تتداخل عملية بدء المرحلة الثانية مع عملية إيقاف الأولى.

يكون ترتيب استدعاءات مراحل النشاط التجاري محدّدًا بشكلٍ واضح، لا سيما عندما يكون النشاطان في العملية نفسها، أي من التطبيق نفسه، وتبدأ الأولى الأخرى. في ما يلي ترتيب العمليات التي تحدث عندما يبدأ النشاط "أ" النشاط "ب":

  1. يتم تنفيذ طريقة onPause() للنشاط "أ".
  2. يتم تنفيذ طرق onCreate() وonStart() وonResume() في النشاط ب بالتسلسل. أصبح النشاط "ب" الآن يركز على المستخدم.
  3. إذا لم يعُد النشاط "أ" مرئيًا على الشاشة، سيتم تنفيذ طريقة onStop().

يتيح لك هذا التسلسل من استدعاءات دورة الحياة إدارة انتقال المعلومات من نشاط إلى آخر.