تصميم سلس

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

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

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

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

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

يناقش هذا المستند مشكلات السلاسة الشائعة وكيفية تجنبها.

عدم إسقاط البيانات

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

وإذا كان المستخدم يعدّل البيانات في تطبيقك عند ظهور النشاط الآخر، من المحتمل أن يفقد تطبيقك هذه البيانات عند إصابة التطبيق. ما لم تكن بالطبع تحفظ العمل الجاري أولاً. هذا وحسب "طريقة Android" ذلك: يجب أن تتجاهل تطبيقات Android التي تقبل الإدخالات أو تعدّلها طريقة onSaveInstanceState()، وأن تحفظ حالتها بطريقة مناسبة. عندما يزور المستخدم التطبيق مرة أخرى، يجب أن تكون قادرة على استرداد بياناته.

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

عدم عرض البيانات الأولية

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

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

لا تقاطع المستخدم

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

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

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

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

هل تريد القيام بالكثير؟ تنفيذ ذلك في سلسلة محادثات

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

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

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

عدم التحميل الزائد على شاشة نشاط واحدة

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

بناءً على خلفيتك في التطوير، يمكنك تفسير نشاط ما على أنه شيء مثل تطبيق Java الصغير، من حيث أنه نقطة دخول تطبيقك. مع ذلك، الأمر ليس دقيقًا تمامًا: فعندما تكون الفئة الفرعية لتطبيق صغير نقطة الدخول الوحيدة لتطبيق Java الصغير، يجب اعتبار النشاط كنقطة من نقاط الدخول العديدة إلى تطبيقك. الاختلاف الوحيد بين نشاطك "الرئيسي" وأي أنشطة أخرى قد تكون لديك هو أنّ النشاط "الرئيسي" هو النشاط الوحيد الذي أبدى اهتمامًا بإجراء "android.intent.action.MAIN" في ملف AndroidManifest..xml.

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

توسيع مظاهر النظام

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

تصميم واجهة المستخدم الخاصة بك للعمل على درجات دقة متعددة للشاشة

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

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

افترض أن الشبكة بطيئة

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

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

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

عدم افتراض أنّ الشاشة تعمل باللمس أو لوحة المفاتيح

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

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

الحفاظ على بطارية الجهاز

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

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

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