لقد قمنا مؤخرًا بإعادة تصميم تطبيق Pyrus لنظام Android. عملت النسخة الأولى من التطبيق بالفعل تحت أندرويد 2.2. رفضًا دعم Android أقل من 4.1 ، تمكنا من تسديد الديون الفنية المتراكمة وتبسيط رمز المصدر بشكل كبير. نعم ، لقد فقدنا جزءًا من المستخدمين (أقل من 1٪) ، ولكن من ناحية أخرى ، وفرنا الوقت للمطورين لإصلاح الأخطاء النادرة. سوف نكون قادرين على استثمارها في تطوير الوظائف لجميع المستخدمين الحاليين والجدد. على المدى الطويل ، هذا أكثر أهمية.
نتبادل هنا التجارب التي قد تكون مفيدة لأولئك الذين يفكرون في بدء تطوير نظام Android الأساسي.
يجذب Android أدوات تطوير جيدة ، لغة تم اختبارها بالوقت (جافا) باستخدام البنية المعتادة ، جمهور كبير من المستخدمين. ومع ذلك ، يعد إنشاء تطبيقات ملائمة على Android أمرًا صعبًا: على الرغم من واجهة برمجة التطبيقات المطورة ، غالبًا ما يحدث عدم وجود مكون جاهز بسلوك مناسب. يجب عليك إما التخلي عن أفكار مصمم UX ، أو الموافقة على الاعتماد على مكتبات الطرف الثالث ، أو الكتابة بنفسك. لم تكن جميع الحلول المعمارية في Android ناجحة ، وهذا يزيد أيضًا من كمية التعليمات البرمجية دون فائدة واضحة.
الموت والصعود من الرماد
تم بناء الواجهة في Android على النشاط. هذه حاوية تشغل عادةً شاشة الجهاز بالكامل ، وعناصر واجهة مستخدم أخرى تعيش فيه وتتلقى أحداثًا حول تفاعل المستخدم.
عندما يقوم المستخدم بتنشيط التطبيق ، يتم طرح حدث onResume في النشاط. الضغط على زر الصفحة الرئيسية - اختفى النشاط ، ولكن قبل ذلك تلقى حدث onPause. كل شيء منطقي حتى الآن. ماذا يحدث عندما يقوم المستخدم بتدوير شاشة الجهاز 90 درجة؟ لن تخمن أبدًا: نظام التشغيل يقتل النشاط ويعيد إنشاؤه! عندما تقوم بإلغاء تثبيت نشاط ، يتم حذف جميع المكونات التي يحتوي عليها. هذا يعني أنه يجب عليك كتابة رمز خاص يحفظ حالة الأدوات داخل النشاط (موضع التمرير ، جزء من النص المحدد ، حالة مربعات الاختيار) واستعادتها بعد إعادة إنشاء الأصل. يقوم Android ببعض هذا العمل من أجلك ، ولكن ليس كل شيء.
من الصعب فهم ما دفع المهندسين المعماريين لاتخاذ مثل هذا القرار. في وقت لاحق ، قرر شخص ما أنه يبدو قبيحًا إلى حد ما ، وأضاف المعلمة نفسها ، التي تمنع السلوك الافتراضي للنظام. الآن ، بدلاً من إعادة إنشاء النشاط ، يمكن لنظام التشغيل استدعاء الأسلوب onConfigurationChanged الخاص. يبدو هذا "الحل" وكأنه اختراق قذر ولا يؤدي إلا إلى تفاقم المشكلة ، لأن وثائق Android
تقول "يجب اعتبار هذه التقنية إجراءً متطرفًا ولا يوصى به لمعظم التطبيقات".
شظايا مجزأة
في البداية ، تم إنشاء نظام تشغيل Android للهواتف. مع ظهور الأجهزة اللوحية ، قرر فريق Android عن حق أن عناصر الواجهة هذه التي كانت متباعدة سابقًا بسبب الأنشطة المختلفة بسبب الحجم الصغير لشاشة الهاتف يمكن أن تتواجد الآن على الشاشة الكبيرة للجهاز اللوحي. (مثال: كانت قائمة الرسائل والبريد الإلكتروني على الهاتف في نشاطين مختلفين ، وعلى الجهاز اللوحي شاركوا شاشة واحدة معًا.) نعم ، المشكلة هي: لا يمكن أن تتفاعل العديد من الأنشطة مع المستخدم حسب التصميم في نفس الوقت. لذلك ، هناك حاجة إلى آلية أخرى لإعادة استخدام المكونات ، وتم العثور على حل: ظهرت شظايا (جزء).
بحكم التعريف ، يمثل الجزء سلوكًا أو جزءًا من واجهة مستخدم في نشاط. كل شيء واضح. ومع ذلك ، في تعليمات استخدام الأجزاء ، نجد القسم "إضافة جزء لا يحتوي على واجهة مستخدم". ماذا؟ اتضح أن الجزء قد لا يكون له نافذة خاصة به للتقديم!
ولكن ماذا يحدث للشظايا عند قلب الشاشة؟ فكر مطورو Android في هذا الأمر - عند إعادة إنشاء نشاط ، يتم أيضًا إعادة إنشاء جميع شظاياه تلقائيًا. ومع ذلك ، عند النظر بعناية ، يكون للجزء طريقة "setRetainInstance" ، إذا سمته ، فلن يتم حذف هذا الجزء واستعادته أثناء المنعطفات.
نحيف ومتسق لا يمكن استدعاء هذا المفهوم.
عملية غير متزامنة
لا يمكن حظر سلسلة معالجة الحدث من خلال عمليات طويلة ، وبالتالي يجب أن يتم تبادل البيانات مع القرص والشبكة بشكل غير متزامن في سلاسل رسائل أخرى. يوفر Android ما يصل إلى أربع آليات للتشغيل غير المتزامن: AsyncTask ، Service ، IntentService ، Thread. يتم تشجيع المطورين لمعرفة أيهما الأفضل لهم لاستخدامه. الاختيار ليس تافهًا: على سبيل المثال ، إذا بدأ التطبيق AsyncTask ، وقلب المستخدم الشاشة أثناء تنفيذه ، فعند الانتهاء من العمل ، لن يتمكن AsyncTask من العثور على نشاط جديد (تم إنشاؤه بعد الانعطاف). ولا تطبق أي من الآليات الأربع منطقًا بسيطًا: إذا بدأ المستخدم العملية غير المتزامنة الثانية دون انتظار نتائج الأولى ، ثم انتهى الأول في وقت سابق ، فمن المناسب تجاهل نتائجه وعدم عكسها في واجهة المستخدم.
يصبح من الواضح ظهور العديد من المكتبات - حافلات البيانات لتنظيم العمل غير المتزامن داخل تطبيق Android.
إعادة تشغيل التطبيق بعد OOM
إذا نفدت ذاكرة الوصول العشوائي في Android ، يمكن لنظام التشغيل إكمال أي عملية. عندما يقوم المستخدم بتنشيط التطبيق في المستقبل ، سيحاول النظام استعادة حالته. من الناحية النظرية ، يجب أن يكون هذا غير مرئي للمطور (إذا قام بتطبيق طريقة onSaveInstanceState في جميع المكونات): يقوم النظام نفسه بإعادة إنشاء حزمة النشاط كما كان أثناء التوقف القسري. ومع ذلك ، إذا استغرقت التهيئة وقتًا (على سبيل المثال ، تحميل ذاكرة التخزين المؤقت من القرص أو من الشبكة) ، فسيكون من الصحيح أن تُظهر للمستخدم مؤشر انتظار. اتضح أنه عند إنشاء نشاط ما ، ما زلت بحاجة إلى مراقبة "البداية الباردة" وتنفيذ التهيئة يدويًا. ناهيك عن أنه عند إعادة التشغيل ، لا تتم استعادة مؤشر الترابط و AsyncTask.
ما مدى احتمالية نفاد الذاكرة عمليًا؟ عادةً ما يحدث هذا الموقف عند معالجة صور عالية الدقة. على سبيل المثال ، تحتل صورة بحجم 2048x1536 مساحة قدرها 12 ميجابايت في ذاكرة كائن الصورة النقطية. يعتمد مقدار الذاكرة المتاح للتطبيق على طراز الجهاز المحدد وأحيانًا يكون صغيرًا جدًا (64 ميجابايت أو 128 ميجابايت). نظرًا لأن جامع القمامة في جميع إصدارات Android قبل الإصدار 8.0 لم يكن مضغوطًا ، حتى إذا كان لديك 100 ميجا بايت من الذاكرة الخالية ، ولكنه مقسم إلى كتل من 10 ميجا بايت ، أدت محاولة تخصيص ذاكرة لمثل هذه الصورة إلى تعطل التطبيق.
مجموعة القمامة الأبدية
بمجرد أن لاحظ مستخدمنا أنه عند التمرير عبر القوائم الطويلة ، يكون التطبيق "متخلفًا" - كل 2-3 ثوان توقف الرسم المتحرك لإيقاف مؤقت قصير (200-300 مللي ثانية) ، ثم استمر. أظهر التحليل أن جمع القمامة يبدأ بشكل مريب في التطبيق. اتضح أن فئة HashMap القياسية (التي نستخدمها للحصول على كائن Java بمعرفها) غير فعالة في حالتنا: نحتاج إلى إنشاء كائن مجمّع لكل مفتاح ، وهو عدد صحيح (int). لذلك ، يزيد عدد عمليات تخصيص الذاكرة دون أي فائدة. كان الحل هو التحول إلى حاوية SparseArray خاصة (متوفرة فقط في Android ، وليس في منصة Java القياسية) ، مما أدى إلى تقليل الضغط على جامع القمامة على الفور.
تسأل ، ما علاقة التأخر في الرسوم المتحركة بذلك؟ والحقيقة هي أن جامع القمامة في Android أوقف جميع سلاسل المحادثات أثناء تشغيله ، بما في ذلك سلسلة المحادثات الرئيسية المشاركة في التقديم. في إصدارات Android التي تبدأ بـ 5.0 ، يتم استخدام آلة افتراضية أخرى (ART بدلاً من Dalvik) وخوارزمية جمع القمامة المختلفة ، مما يؤدي إلى إيقاف الرسوم المتحركة مؤقتًا أقل وأقل. (يمكنك القراءة عن مقارنة وقت جمع القمامة
هنا .)
عرض المستندات
إذا كنت تريد إدراج معاينات المستند في تطبيقك ، فأنت مضطر إلى خيبة الأمل: في Android لا يوجد مكون مدمج يمكنه عرض ملفات Word و Excel و Powerpoint. ناهيك عن أرشيفات ZIP أو مستندات PDF. مخرج؟ إجبار المستخدم على تثبيت تطبيقات الجهات الخارجية لعرض كل نوع من الملفات أو استخدام مكون WebView (متصفح فعليًا). في كلتا الحالتين ، عندما يضغط المستخدم على الملف ، سيتم تشغيل تطبيق خارجي ولا يمكن تنفيذ بعض السيناريوهات ، على سبيل المثال ، تغذية صورة: لا توجد طريقة سهلة لدمج WebView في ViewPager قياسي.
ما هي الخطوة التالية
تدعي بعض الدراسات أن
تعقيد تطوير Android مرتفع نسبيًا . تظهر تجربتنا أنه من السهل على مطور كفؤ التعود على ميزات هذا النظام الأساسي. وعلى الرغم من أن نظام التشغيل Android هو اليوم نظام التشغيل
الأكثر شيوعًا للجوال في العالم ، فقد يتغير الوضع بشكل جذري في 5-10 سنوات.
في السنوات الأخيرة ، قامت Google سرًا بتطوير
Fuchsia OC الجديد مع نموذج أمان مختلف تمامًا (مقارنة بنظام التشغيل الحديث). من المحتمل أن تستخدم
Dart كلغة برمجة رئيسية ، وإطار
Flutter كطريقة رئيسية لإنشاء التطبيقات. يشاع أن
Fuchsia يمكن أن يحل محل Android و ChromeOS على جميع الأجهزة. إذا قامت Google بذلك ، فمن المرجح أن تقدم الشركة دعمًا أصليًا للتطبيقات المكتوبة لنظام Android (كما فعلت Microsoft عند التبديل من DOS إلى Windows). لذلك ، حتى الآن لا داعي للقلق والاستمرار في تراكم الخبرة في Android. ولأولئك الذين يرغبون في النظر إلى المستقبل ، يمكنك تنزيل Flutter واللعب به
هنا .