التعرف على نشاط LaunchMode لنظام Android: قياسي ، فردي ، مهمة فردية وحيدة

تم إعداد ترجمة المقالة خصيصًا للطلاب المتقدمين في تطوير Android .




يعد النشاط أحد أكثر المفاهيم اللافتة للانتباه في Android (نظام التشغيل المحمول الأكثر شيوعًا مع بنية إدارة ذاكرة مصممة جيدًا والتي تنفذ المهام المتعددة بشكل مثالي).

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

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

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

تعريف LaunchMode


بشكل أساسي ، يمكننا تعريف launchMode مباشرة كسمة علامة <activity>في AndroidManifest.xml:

<activity
    android:name=".SingleTaskActivity"
    android:label="singleTask launchMode"
    android:launchMode="singleTask">

هناك 4 أنواع متاحة من LaunchMode. دعونا نلقي نظرة عليها في وقت واحد.

معيار

هذا هو الوضع الافتراضي.

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

السلوك على Android قبل إصدار Lollipop

سيتم إنشاء هذا النوع من النشاط ووضعه أعلى المكدس في نفس المهمة التي أرسلت Intent.



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



وهذا ما ستراه في مدير المهام. (قد يبدو الأمر غريبًا بعض الشيء)



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

السلوك على Android Lollipop

إذا كانت هذه الأنشطة تتعلق بالتطبيق نفسه ، فسيكون السلوك هو نفسه كما هو الحال في تنفيذ ما قبل Lollipop - مع وضع المكدس أعلى المهمة.



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



هذا ما ستراه في مدير المهام.



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



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

أحادي


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



في وضع singleTop، يجب عليك أن تنظر التعامل مع في النوايا واردة onCreate()و onNewIntent()بحيث أنه يعمل في جميع الحالات.

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

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

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

على أي حال ، يعمل singleTop في نفس مهمة المتصل. إذا كنت تتوقع أن يتم إرسال Intent إلى نشاط حالي ، يتم وضعه على رأس أي مهمة أخرى ، يجب أن أخيب ظنك بقول أنه لم يعد يعمل. في حالة إرسال Intent من تطبيق آخر إلى نشاط SingleTop ، فسيتم إطلاق النشاط الجديد في نفس الجانب الخاص بالنمط القياسي لبدء التشغيل (pre-Lollipop: تم وضع Lollipop أعلى مهمة الاستدعاء ، Lollipop: سيتم إنشاء مهمة جديدة) .

مهمة واحدة


هذا الوضع يختلف تمامًا عن الوضع القياسي والأعلى. يُسمح بالنشاط باستخدام singleTask launchMode أن يكون له مثيل واحد فقط في النظام (ala singleton) . إذا كان مثيل النشاط موجودًا بالفعل في النظام ، فسيتم نقل المهمة بالكامل التي تحتفظ بالمثيل لأعلى ، وسيتم توفير Intent من خلال الطريقة onNewIntent(). خلاف ذلك ، سيتم إنشاء نشاط جديد ووضعه في المهمة المقابلة.

العمل في تطبيق واحد

إذا لم يكن هناك مثيل واحد لنشاط المهمة في النظام ، فسيتم إنشاء مثيل جديد وسيتم ببساطة وضع المكدس في نفس المهمة.



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



لا معنى له من وجهة نظر تجربة المستخدم ، ولكنه مصمم بهذه الطريقة ...

يمكنك ملاحظة فارق بسيط واحد مذكور في الوثائق :

يقوم النظام بإنشاء مهمة جديدة وإنشاء مثيل نشاط في جذر المهمة الجديدة.

ولكن من الناحية العملية ، يبدو أن هذا لا يعمل كما هو موضح . لا يزال يتم وضع نشاط SingleTask في أعلى رصة النشاط للمهمة ، كما يمكن رؤيته من نتيجة الأمر dumpsys activity.

تا

sk id #239
  TaskRecord{428efe30 #239 A=com.thecheesefactory.lab.launchmode U=0 sz=2}
  Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.thecheesefactory.lab.launchmode/.StandardActivity }
    Hist #1: ActivityRecord{429a88d0 u0 com.thecheesefactory.lab.launchmode/.SingleTaskActivity t239}
      Intent { cmp=com.thecheesefactory.lab.launchmode/.SingleTaskActivity }
      ProcessRecord{42243130 18965:com.thecheesefactory.lab.launchmode/u0a123}
    Hist #0: ActivityRecord{425fec98 u0 com.thecheesefactory.lab.launchmode/.StandardActivity t239}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.thecheesefactory.lab.launchmode/.StandardActivity }
      ProcessRecord{42243130 18965:com.thecheesefactory.lab.launchmode/u0a123}

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

<activity
    android:name=".SingleTaskActivity"
    android:label="singleTask launchMode"
    android:launchMode="singleTask"
    android:taskAffinity="">

ستكون هذه النتيجة عندما نحاول الركض SingleTaskActivity.





مهمتك هي أن تقرر ما إذا كنت ستستخدم taskAffinityأم لا اعتمادًا على السلوك المطلوب للنشاط.

التفاعل مع تطبيق آخر

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





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



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



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

نسخة واحدة


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

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

هذا ما يحدث عندما يتم استدعاء نشاط فردي أثناء وجود نشاط بالفعل على المكدس.



وهذا ما نراه في مدير المهام.



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

على أي حال ، هناك بعض الحلول لهذه المشكلة. كما هو الحال مع نشاط singleTask ، ما عليك سوى تعيين سمة taskAffinityلنشاط singleInstance ، مما يسمح بوجود مهام متعددة في إدارة المهام.

<activity
    android:name=".SingleInstanceActivity"
    android:label="singleInstance launchMode"
    android:launchMode="singleInstance"
    android:taskAffinity="">

الآن الصورة أكثر منطقية.



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

أعلام النية


بالإضافة AndroidManifest.xmlإلى تعيين وضع التشغيل مباشرة على ، يمكننا أيضًا ضبط السلوك باستخدام أداة تسمى إشارات Intent ، على سبيل المثال:

Intent intent = new Intent(StandardActivity.this, StandardActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);

سيتم إطلاقه StandardActivityمع الشرط المفردة

هناك عدد غير قليل من الأعلام التي يمكنك العمل معها. يمكنك العثور على مزيد من المعلومات حول هذا هنا .

آمل أن تكون قد وجدت هذه المقالة مفيدة =)

تعرف على المزيد حول الدورة التدريبية

All Articles