لماذا فوز Flutter؟

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


القليل من التاريخ


صححني إذا كنت مخطئًا ، لكن عام 2009 كان من نواح كثيرة مفتاحًا لتطوير الأجهزة المحمولة بشكل عام والتطوير عبر الأنظمة الأساسية بشكل خاص. في عام 2009 ، تم إصدار iPhone 3gs ، مما سمح لك بتشغيل تطبيقات الطرف الثالث من AppStore. لأول مرة ظهرت هذه الفرصة قبل ذلك بعام في iPhone 3g ، لكن 3gs أصبح جهاز iPhone ضخمًا وشعبيًا حقًا. مرة أخرى ، قبل عام ، في سبتمبر 2008 ، تم تقديم Android للجمهور وفي عام 2009 بدأ العديد من مصنعي الهواتف في تجربة Android لطرازات هواتفهم الجديدة. في ربيع 2009 ، قدم Nitobi PhoneGap ، وهو إطار جديد لإنشاء تطبيقات عبر الأنظمة الأساسية تعتمد على HTML5 و CSS و JS. في نفس العام ، في سبتمبرأصدر Ximian MonoTouch ، مما سمح لك بكتابة تطبيقات iOS باستخدام Mono و C #. في نفس عام 2009 ، في ديسمبر ، أصدرت Rovio Entertainment لعبة لنظام التشغيل iOS ، ولحظة ما ، Maemo ، والتي تمثل من نواح عديدة بداية صناعة ألعاب الهواتف المحمولة - Angry Birds. المثال الأخير هنا ليس صدفة.

يمكن اعتبار أول إطار عمل متعدد المنصات "للشعب" PhoneGap (مطورو Qt ، لا ترموا الحجارة). لقد كانت فكرة رائعة وواضحة - إدخال الويب في عالم تطوير الأجهزة المحمولة. بحلول عام 2009 ، كانت إمكانات الويب قد بدأت بالفعل في التوسع إلى ما بعد المتصفح ( hello node.js) ، بينما كانت كتابة تطبيقات الويب في JS بسيطة جدًا. النقطة الثانية ، التي لا تقل أهمية ، هي عرض واجهة المستخدم. الطريقة التي يحدث بها العرض تكمن في محرك المتصفح وكل هذه المحركات تتبع بشكل أو بآخر معايير W3C لـ HTML و CSS و DOM. أي مطور ويب قام بتكوين موقع يتوقع أن موقعه سيبدو تقريبًامتطابقة في أي متصفح وعلى أي منصة. هذا ، في رأيي ، هو أهم جانب من الويب كمنصة مفتوحة. لماذا يجب أن أتعلم لغة / إطار عمل جديد لرسم واجهة المستخدم لكل نظام أساسي ، إذا كان هناك معيار لفترة طويلة لنمذجة واجهة المستخدم لمتصفحات مختلفة.

بعد ذلك ، انطلق كوردوفا من PhoneGap ، ومنه أيوني. يبدو أن هذا إطارًا مثاليًا ، ولكن كانت هناك نقطتان: الأداء وتكامل نظام التشغيل. كان أحد الأهداف الرئيسية أو ، إذا كنت تريد ، معايير التطبيق ، المكتوبة على حلول عبر الأنظمة الأساسية هو "المهد". أولئك. من الناحية المثالية ، يجب أن يعتبر 100٪ من المستخدمين أن تطبيقك عبر الأنظمة الأساسية أصلي. وهذا يعني أنه يجب أن يبدو الأصلي ، ويعمل مثل الأصلي ولديه كل التكامل الممكن مع نظام التشغيل. في البداية ، كانت جميع هذه النقاط لـ PhoneGap غير قابلة للتحقيق ، وقدرات الهواتف الذكية قبل 10 سنوات لم تكن كافية لعرض واجهة المستخدم 60 إطارًا في الثانية ، وكان التكامل مع نظام التشغيل ضئيلاً. الآن هناك عدد غير قليل من التطبيقات على Ionic يصعب تمييزها عن التطبيقات الأصلية ، ولكن محاكاة التطبيق الأصلي لا يزال مهمة.ولا تعطى على هذا النحو. دعونا نلخص قليلا. كتابة تطبيقات الويب ، أو تطبيقات مختلطة إلى حد ما على نظامي iOS و Android ، أمر ممكن وملائم. إنها مريحة لأن آلية عرض واجهة المستخدم تقع بالكامل على منصة WebView ، بالإضافة إلى وجود طبقة مدربة بالفعل من المبرمجين الذين لديهم دراية جيدة على الويب.ومع ذلك ، في التطبيقات المختلطة ، قد يكون الأداء ودمج نظام التشغيل عرجاء.

في نفس وقت PhoneGap ، تم إطلاق MonoTouch في عام 2009 ، والتي أعيدت تسميتها لاحقًا Xamarin.iOS. أيضًا ، في نفس العام ، تم إصدار Titanium ، والذي سمح بدوره بكتابة تطبيقات iOS على جافا سكريبت. في البداية ، عمل Titanium في نفس النموذج تمامًا مثل PhoneGap - بالاعتماد على WebView. ولكن بعد ذلك اعتمدوا نهج Xamarin. ما هذا النهج؟ يمكن أن ينظر إليه على أنه شيء في الوسط. نهج Xamarin / Titanium / React.Native هو أنه بدلاً من محاولة إنشاء / ترحيل عرض واجهة المستخدم / الموجود لديك ، فإن الإطار يتكامل ببساطة مع المحتوى الحالي الأصلي.

بدلاً من رسم نموذج بتنسيق HTML ، يستدعي Xamarin عنصر واجهة مستخدم أصلي لهذا (UITextField ، TextEdit ، إلخ). في الواقع ، لماذا إعادة اختراع العجلة؟ توجد جميع عناصر واجهة المستخدم الضرورية في حزم SDK وأوقات التشغيل الأصلية ، ما عليك سوى معرفة كيفية التواصل معهم من الأجهزة الافتراضية (أحادية ، v8 ، إلخ). في نفس الوقت ، كما توقعت بالفعل ، يمكنك استخدام C # ، JS ، TS ، F # ، Kotlin ، إلخ المفضلة لديك ، وفي نفس الوقت الرمز الذي لا يتفاعل مباشرة مع واجهة المستخدم هو 100٪ عبر الأنظمة الأساسية. يمكنك الذهاب إلى أبعد من ذلك. نفس UITextField و TextEdit هما كيانان متطابقان من الناحية المفاهيمية ، ولديهما بعض الخصائص وواجهات التفاعل المتشابهة ، وبالتالي ، يمكنك إنشاء إدخال تجريدي (hello Xamarin.Forms) والعمل معه فقط ، نادرًا ( ليس جدًا) استثناء النزول إلى عنصر واجهة المستخدم للنظام الأساسي. لا أذكر أنه إذا كان بإمكان vm الخاص بك العمل مع واجهة المستخدم أصلاً ، فمن المحتمل أن vm الخاص بك يمكنه الاتصال بأي واجهات برمجة تطبيقات للنظام الأساسي. يبدو أن هذا هو الخيار المثالي. واجهة مستخدم أصلية ، أداء محلي (hi Bridges in React.Native) ، تكامل نظام التشغيل 100٪. هل هذا مثالي حقًا؟ على الأرجح - لا ، والمشكلة هي أن هذه الحلول في الواقع لا تحل مشكلة التطوير عبر الأنظمة الأساسية - واجهة مستخدم واحدة. يخفونها. أريد أن أكتب مرة واحدة ، أركض في كل مكان. هذا أبعد ما يكون عن أفضل شعار لجميع أنواع البرامج والمشكلات ، ولكنه يناسب بشكل جيد واجهة المستخدم. أريد أن أكتب واجهة المستخدم نفسها للجميع ، بغض النظر عن النظام الأساسي. لماذا يسمح مطور الويب لنفسه باستخدام HTML و CSS لكتابة موقع يتم عرضه بنفس الطريقة في Safari على iOS و Chrome على Android ، ولكن لا يوجد مطور أصلي؟

في الواقع ، لقد كتب المبرمجون منذ فترة طويلة واجهة مستخدم عالية الأداء مع قاعدة رمز مشتركة لنظامي التشغيل iOS و Android. ويطلق على هؤلاء المبرمجين مطوري الألعاب. تم كتابة Angry Birds على محرك Cocos2d-x و Cuphead on Unity و Fortnite على محرك Unreal. إذا كانت محركات الألعاب قادرة على إظهار مشاهد خلابة على هاتفك ، فإن الأزرار والقوائم ذات الرسوم المتحركة السلسة ستكون بالتأكيد قادرة على ذلك. فلماذا لا يستخدمهم أحد في هذا السياق؟ الإجابة بسيطة ومبتذلة ، فهي ليست معدة لهذا الغرض. عندما تفتح اللعبة ، يعود الأمر إلى المصباح تمامًا إلى أي مدى تبدو واجهة المستخدم وكأنها واحدة أصلية ، فلن تحتاج أبدًا إلى التفاعل مع تحديد الموقع الجغرافي ، وأزرار الضغط ، وكاميرا الفيديو ، وما إلى ذلك. أثناء اللعب ، تعيش حياة مختلفة في عالمك الصغير يتم تقديمها من خلال Canvas في UIViewController / Activity. وبالتاليتتمتع محركات الألعاب بتكامل ضعيف نسبيًا مع نظام التشغيل ، لذلك لا يوجد (أو لم أره) يحاكي المحرك العلوي الأصلي لواجهة المستخدم.

المجاميع الفرعية


للحصول على إطار عمل مثالي عبر الأنظمة الأساسية ، نحتاج إلى:

  • تعيين واجهة المستخدم الأصلية
  • أداء واجهة المستخدم الأصلية
  • قدرة 100٪ على الاتصال بأي API OS كما لو كان تطبيق أصلي

أنت تعتقد الآن أنني سأبدأ في الفشل تحت Flutter ، لكني أسمع بالفعل تعليقات غاضبة: "أين Qt!؟ يمكنه أن يفعل كل هذا! " في الواقع ، Qt إلى درجة أو أخرى يناسب هذه المعايير. على الرغم من أنني أشك بقوة في أولهم. لكن المشكلة الرئيسية لـ Qt ليست صعوبة كتابة واجهة مستخدم أصلية ، المشكلة الرئيسية هي C ++. ثم أقوم بالفعل بمسح وجهي من بصق مشفرات العمل على الإيجابيات. الايجابيات هو سكين سويسري على المنشطات ، على الايجابيات يمكنك القيام بكل شيء. لكنني ، بصفتي مطورًا أماميًا ، لست بحاجة إلى كل هذا. أحتاج إلى لغة بسيطة ومفهومة تعمل مع واجهة المستخدم و I / O. لذلك ، تمت إضافة النقاط الثلاث أعلاه:

  • سهلة التعلم ولغة معبرة للغاية
  • وقت مناسب تمامًا في نموذج تطوير الواجهة الأمامية

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

تعيين واجهة المستخدم الأصلية



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


إذا ذهبت إلى قسم كوبرتينو ، سترى أن هذه الأدوات لا يمكن تمييزها عن عناصر iOS الأصلية. كمطور يستخدم Flutter منذ فترة ، يمكنني أن أؤكد أنه لا يمكن تمييزه. إذا كنت تستخدم CupertinoDatePicker ، على سبيل المثال ، عند التمرير ، ستشعر تمامًا بالتعليقات نفسها ، من تعليقات Taptic / Haptic على جهاز iPhone الخاص بك كما لو كانت عنصرًا أصليًا في التطبيق الأصلي. سأقول المزيد ، بشكل دوري ، أفتح تطبيق موقع realtor.com على جهاز iPhone الخاص بي وحتى وقت قريب لم يكن لدي أي فكرة عن أنه مكتوب في Flutter (أو على شيء غير أصلي).

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

نقطة أخرى رائعة. يدعم Flutter الأنظمة الأساسية التي تبدأ بـ iOS 8 و Android API v16. من منظور عرض واجهة المستخدم ، لا يهم Flutter حقًا واجهات برمجة التطبيقات المتاحة على نظام أساسي معين. ستتاح له الفرصة للعمل مع Canvas ونوع من التفاعل مع النظام الفرعي للرسومات. وهذا يعني أنه يمكننا رسم أحدث عناصر واجهة المستخدم من AndroidX ، على سبيل المثال ، على هاتف عمره 8 سنوات. هناك بالتأكيد سؤال حول أداء هذا النهج على أقدم المنصات المدعومة ، ولكن هذا سؤال آخر.

أداء واجهة المستخدم الأصلية



كما ترون ، فإن نهج Flutter لتقديم واجهة المستخدم أقرب إلى التطبيقات المختلطة مثل Ionic. لدينا محرك واحد لعرض واجهة المستخدم على جميع المنصات ، هذه مكتبة Skia Graphics. اشترت Google Skia كمنتج في عام 2005 وحولته إلى مشروع مفتوح المصدر. هذا يشير على الأقل إلى أن هذا منتج ناضج إلى حد ما. بعض ميزات أداء Skia:

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

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

يمكن لـ Skia التفاعل مع العديد من واجهات GPU الخلفية. منذ الآونة الأخيرةالوقت على iOS ، منذ الإصدار 11 ، يستخدم Flutter Metal باعتباره GPU الخلفية بشكل افتراضي. على نظام Android ، بدءًا من API 24 - Vulkan. للإصدارات أدناه - OpenGL. كل هذا يعطينا مكاسب واضحة في الإنتاجية. على منصات "الأجهزة" الأخرى ، كما أفهمها ، تستخدم Skia / Flutter برنامج OpenGL ، الذي لا يمنعنا من حيث المبدأ من كتابة التطبيقات بأداء رسومات كافٍ.

ويب يقف بعيدا. في الوقت الحالي ، لا يزال عرض واجهة المستخدم بالكامل موجودًا على حزمة Canvas / HTML. لذلك ، لا تشارك Skia بأي شكل من الأشكال في هذه العملية. بالإضافة إلى ذلك ، لا يتفاعل Dart VM مباشرة مع DOM. يأتي أولاً التحويل إلى js. كل هذا ليس له أفضل تأثير على الإنتاجية ويمكن ملاحظته مباشرة بالعين المجردة. ومع ذلك، العمل هو جار لتنفيذ CanvasKitفي Flutter ، والذي بدوره سيسمح باستخدام Skia في المتصفحات عبر WebGL.

أخيرًا ، يستخدم مبرمجو C # SkiaSharp لفترة طويلة نسبيًا - وهو غلاف فوق Skia لـ Mono / .Net x. ويستخدم مجتمع Xamarin هذا lib لرسم عناصر واجهة المستخدم المخصصة وهذه مكتبة شائعة جدًا. إذا لم يكن هذا انتصارًا ، فأنا لا أعرف ما هو.

100٪ القدرة على الاتصال بأي API OS


في Flutter هناك مبدأان للتفاعل مع العالم "الخارجي":


تسمح لك قنوات النظام الأساسي بالتفاعل مع وقت التشغيل / واجهة برمجة التطبيقات الأصلية من خلال نظام المراسلة. من وجهة نظر معمارية ، يمكن رؤية ذلك على النحو التالي. بصريا ، Flutter هو لوحة قماشية فقط ، والتي تمتد إلى ملء الشاشة في النشاط / UIViewController الوحيد لتطبيقك الأصلي. هذا هو بالضبط نفس النهج الذي أستخدمه مطوري الألعاب (محركات الألعاب). أولئك. يمكنك فتح مشروع iOS / Android لتطبيقك وإضافة أي وظائف أخرى إلى Swift / Kotlin / إلخ. تكمن المشكلة في أن وقت التشغيل الأصلي و Dart VM لن يعرفوا أي شيء عن بعضهم البعض (بالإضافة إلى حقيقة أن وقت التشغيل الأصلي سيعرف أن التطبيق يحتوي على Canvas وشيء معروض هناك). علاوة على ذلك ، إذا قمت ، على سبيل المثال ، بفتح ملف MainActivity.kt الخاص بمشروع Android ، فسترى شيئًا مثل هذا:

class MainActivity: FlutterActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    GeneratedPluginRegistrant.registerWith(this)
  }
}

هل لاحظت أن نشاطك يرث من FlutterActivity؟ يمنحنا هذا الفرصة لتهيئة آلية إرسال الرسائل مباشرة إلى Flutter / DartVM. للقيام بذلك، ونحن بحاجة لتجاوز configureFlutterEngine طريقةوستحدد اسم الطريقة المطلوبة واسم القناة لإرسال الرسائل غير المتزامنة. الكل. هذا يجعل من الممكن أن يكتب لنا أي رمز أصلي والاتصال بأي API الأصلي! في الوقت نفسه ، يوجد بالفعل عدد كبير من المكونات الإضافية (الحزم) التي توفر عليك من كتابة التعليمات البرمجية الأصلية ، يمكنك استخدام Dart فقط. هذا رائع! تكتب واجهة المستخدم بشكل منفصل ومرة ​​واحدة لأي نظام أساسي ، استخدم DartVM للعمل مع واجهة المستخدم ، I / O وكمكون حوسبي ، استخدم المكونات الإضافية التي تنفذ الميزات الأصلية والتي تغطي 99 ٪ من جميع الوظائف. وإذا لم يكن ذلك كافيًا ، فأنت تكتب أصلاً وتتواصل من خلال آلية الرسالة. قصة.

الآلية الثانية هي واجهة وظيفة أجنبية أو FFI. هذا مصطلح شائع إلى حد ما لآلية iterope مع لغات أخرى ، بشكل رئيسي C. في عالم .Net ، تسمى هذه الآلية P / Invoke ، أما JVM فهي JNI. باختصار ، هذه هي القدرة على التفاعل مع المكتبات المكتوبة بلغة C / C ++ / إلخ. في وقت .Net Framework ، على سبيل المثال ، لم يكن هناك برنامج مكتوب بلغة C # وكانت الغالبية العظمى من البرامج مكتوبة بلغة C / C ++ ، لذلك كانت هناك حاجة إلى آلية للعمل مع هذه المكتبات. الأمر نفسه ينطبق على JVM ، Python ، سمها ما شئت. FFI هو بطريقة أو بأخرى يستخدم في جميع أطر الهاتف المحمول عبر الأنظمة الأساسية. في الآونة الأخيرة ، بدأت DartVM أيضًا في دعم FFI للتفاعل مع C و JavaScript! عندما تكون هذه الميزة في فرع بيتا ، ولكنها متاحة بالفعل للاستخدام (على مسؤوليتك الخاصة والمخاطر).

كما ترون ، فإن Flutter و DartVM يغطيان 100٪ من الاحتمالات على الأنظمة الأساسية الأصلية ، وأكثر من ذلك.

سهلة التعلم ولغة معبرة للغاية


أعترف بصدق ، في حين أن Dart بالنسبة لي لا تزال ليست أفضل لغة في العالم. لا يوجد نظام صارم من النوع ، ولا توجد كعكات وظيفية ، مثل ميزات مطابقة الأنماط أو عدم الثبات (مثل سيتم تسليمها قريبًا) ، إلخ. حول نظام النوع ، تم تصميم Dart في الأصل على أنه لغة "بدون لغة نموذجية" ، ala JS ، ولكن بالنسبة للدعم العادي لتجميع AOT ، كان من الضروري مع ذلك جعل نظام النوع أكثر صرامة ، على الرغم من أنه ليس تمامًا ، أود أن أقول. لا يزال يزعجني العمل مع توقيعات الطريقة ، أي مع الحجج. كل هذه الأقواس غاضبة @requiredلسبب ما . لكن السهام لغة سهلة التعلم. في بناء الجملة ، هذا هو تقاطع بين Java و JS بالنسبة لي. دارت يغفر الكثير ، مثل شبيبة. بشكل عام ، هذه لغة سهلة إلى حد ما لتعلم اللغة ، لم أواجه أي مشاكل كبيرة.

وقت مناسب تمامًا في نموذج تطوير الواجهة الأمامية


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

يعزل

دارت VM لديها مفهوم العزلة. Isolate هو مزيج من مؤشر ترابط رئيسي يتم تشغيله مباشرة على رمز Dart والكومة المنعزلة ، حيث يتم تخصيص الكائنات من رمز Dart بالفعل. هذا هيكل مبسط. يحتوي Isolate أيضًا على خيوط مساعدة / نظام ، وهناك سلاسل عمليات لنظام التشغيل يمكنها الدخول إلى Isolate والخروج منه ، إلخ. المكدس موجود أيضًا في Isolate ولكنك ، كمستخدم ، لا تعمل عليه. الشيء الرئيسي الذي يجب التأكيد عليه هنا هو أنه إذا نظرت إلى عزلة واحدة ، فهذه بيئة خيط واحد. افتراضيًا ، يستخدم Flutter عزلًا افتراضيًا واحدًا. هل يشبه أي شيء؟ نعم هذه بيئة شبيبة. تمامًا كما هو الحال في JS ، لا يمكن لمبرمجي Dart العمل مع مؤشرات متعددة. قد يعتقد شخص ما أن هذه فوضى وتبسيط وانتهاك لحقوق المطورين الحقيقيين ، ولكن أعتقد أنه عند العمل مع واجهة المستخدم ،عندما تعمل باستخدام DOM مشروط (ولا ترسم مضلعات على الشاشة) ، لا تحتاج إلى ذلك ، من الخطر العمل بعدة سلاسل.

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

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

Young Space Scavenger (و Parallel Mark Sweep)

أولاً ، مثل جميع GCs ، فإن GC في Dart VM لديه أجيال. أيضا ، يمكن تقسيم GC في Dart VM وفقًا لمبدأ العمل إلى مكونين: Young Space Scavenger و Parallel Mark Sweep. لن أتطرق إلى المبدأ الأخير ، فهذا مبدأ شائع إلى حد ما في تنظيف الذاكرة ، والذي يتم تنفيذه في كل مكان تقريبًا ولا يمنح Flutter ميزة خاصة. نحن مهتمون بالأول. يتم توضيح مبدأ عمل Young Space Scavenger بشكل جيد في الصورة التالية:


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

Idle Time GC

كما تفهم ، تعمل فرق Flutter و Dart VM معًا بشكل وثيق ويمكن اعتبار نتيجة هذا التعاون Idle Time GC. كما يوحي الاسم ، هذه هي مجموعة القمامة في الوقت الذي لا يحدث فيه شيء. في سياق Flutter ، في اللحظة التي لا يغير فيها التطبيق بصريًا أي شيء. لا توجد رسوم متحركة أو تمرير أو تفاعل من المستخدم. في هذه اللحظات ، يرسل Flutter رسائل إلى Dart VM أصبحت الآن ، من حيث المبدأ ، وقتًا جيدًا لبدء جمع القمامة. بعد ذلك ، يقرر جامع القمامة ما إذا كان يجب أن يبدأ عمله. وبالطبع ، فإن جمع القمامة في هذا الصدد يحدث للكائنات القديمة التي تتم إدارتها من خلال Parallel Mark Sweep ، وهو في حد ذاته عملية مكلفة إلى حد ما ويعتبر Idle Time GC آلية مفيدة جدًا في هذا الصدد.

هناك أشياء أخرى مثلانزلاق الدمك و مضغوط مؤشرات . الأول هو آلية إلغاء تجزئة الذاكرة بعد تشغيل Parallel Mark Sweep. هذه أيضًا عملية مكلفة وتعمل فقط إذا كان هناك وقت خمول. يقوم الأسلوب الثاني ، Compressed Pointers ، بضغط مؤشرات 64 بت في 32 بت ، مما يوفر الذاكرة (أعتقد أن هذا أكثر فائدة في بيئة الخادم من الجوال).

ملخص


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

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

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

All Articles