Flutter: تعذر استدعاء طريقة قناة النظام الأساسي من عزل آخر

تم إنشاؤها على ٥ يناير ٢٠١٨  ·  133تعليقات  ·  مصدر: flutter/flutter

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

إذا لم يكن الأمر كذلك ، فمن المحتمل أن نذكر ذلك في مكان ما.

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

P5 annoyance crowd gold engine framework passed first triage plugin crash new feature

التعليق الأكثر فائدة

لدي حالات استخدام مختلفة ، على سبيل المثال:

  • قم بتنزيل وتحليل جزء كبير من البيانات (dart: تحويل الطرق ليست غير متزامنة) ، ثم قم بتخزينها في sqlite db باستخدام البرنامج المساعد sqflite (الذي يستخدم روابط النظام الأساسي) ؛
  • الجلب المسبق للبيانات وتحليلها قبل تقديمها إلى واجهة المستخدم ؛
  • تشفير / فك تشفير وقراءة / كتابة البيانات من / إلى ملف (تتم عمليات التشفير من خلال قناة طريقة من أجل استخدام libs أمان النظام الأساسي) ؛

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

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

ومع ذلك ، فقد تعطلت قليلاً أثناء التنفيذ: هل يمكنك تقديم مثال على طريقة سهلة لاستدعاء طريقة ثابتة على العزل الرئيسي عن طريقة ثانوية؟

شكرا

ال 133 كومينتر

cc @ mravn-google لفرز الفرز

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

كحل (أخرق) ، يمكن للعزل الثانوي أن يطلب من الشخص الأساسي إرسال الرسالة.

sroddy قد أسأل ما الذي تحاول تحقيقه مع العزلة الثانوية؟

لدي حالات استخدام مختلفة ، على سبيل المثال:

  • قم بتنزيل وتحليل جزء كبير من البيانات (dart: تحويل الطرق ليست غير متزامنة) ، ثم قم بتخزينها في sqlite db باستخدام البرنامج المساعد sqflite (الذي يستخدم روابط النظام الأساسي) ؛
  • الجلب المسبق للبيانات وتحليلها قبل تقديمها إلى واجهة المستخدم ؛
  • تشفير / فك تشفير وقراءة / كتابة البيانات من / إلى ملف (تتم عمليات التشفير من خلال قناة طريقة من أجل استخدام libs أمان النظام الأساسي) ؛

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

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

ومع ذلك ، فقد تعطلت قليلاً أثناء التنفيذ: هل يمكنك تقديم مثال على طريقة سهلة لاستدعاء طريقة ثابتة على العزل الرئيسي عن طريقة ثانوية؟

شكرا

sroddy شكرًا على توفير المعلومات الأساسية.

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

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

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

الحل موضح أدناه.

لنفترض أنك قمت بإعداد المنفذين M1 و R1 على العزلة الرئيسية و M2 و R2 على العزلة الثانوية. M للرسالة ، R للرد.

  • في العزل الثانوي الخاص بك ، استخدم BinaryMessages.setMockMessageHandler لكل قناة لإعادة توجيه الرسائل للنظام الأساسي إلى M1 (بشفافية إلى المكون الإضافي الذي يستخدم BinaryMessage.send مع تلك القناة). قم بتخزين عمليات رد نداء الرد وقم بتكوين R2 باستخدام معالج يستدعي المعالِج الصحيح عند استلام الرد على الرسالة. قم بتكوين M2 باستخدام معالج يقوم بإعادة التوجيه إلى BinaryMessages.handlePlatformMessage . قم بتنفيذ رد الاتصال هناك لإعادة توجيه الردود إلى R1.
  • بشكل متماثل في عزلتك الرئيسية. قم بتكوين M1 باستخدام معالج يقوم بإعادة توجيه الرسائل للنظام الأساسي إلى BinaryMessages.send . قم بتعيين رد اتصال يقوم بإعادة توجيه الردود من النظام الأساسي إلى R2. اتصل أيضًا بـ BinaryMessages.setMessageHandler لكل قناة لإعداد معالج للرسائل الواردة من النظام الأساسي الذي يعيد التوجيه إلى M2. قم بتخزين عمليات رد نداء الرد وقم بتكوين R1 باستخدام معالج يستدعي المعالِج الصحيح عند استلام رد من العزل الثانوي.

Hixie أقترح الانتقال إلى المرحلة التالية. يبدو أن الحل موجود. سيتطلب الحل الجيد بعض أعمال تصميم واجهة برمجة التطبيقات وتكرارها.

لدي نفس المشكلة ، أي أخبار عن هذا الموضوع؟

@ mravn-google هل لديك أي تحديث حول هذا؟ واجهت نفس المشكلة (أحتاج إلى إنشاء زوج مفاتيح RSA 2048 على سبيل المثال على جانب النظام الأساسي والذي يستغرق بعض الوقت على الأجهزة القديمة أو تشفير / فك تشفير البيانات). أفضل تجنب إنشاء سلاسل رسائل أو خدمات لأن ذلك من شأنه أن يضاعف عملي على جانب النظام الأساسي لأنه سيتم تنفيذه على كل من أنظمة Android و iOS. هل لدينا أي طريقة سهلة لتشغيل هذه العمليات الخاصة بالمنصة بشكل غير متزامن من Dart؟ يبدو أن الحل البديل الخاص بك على ما يرام ، ولكن يبدو أن لدي بعض المشكلات في تنفيذ ذلك لأنني جديد تمامًا على Flutter و Dart (لست متأكدًا من كيفية تكوين معالج يعيد توجيه الرسائل إلى Isolate وما إلى ذلك) ، آسف عن ذلك.

حصلت على نفس القضية.

أحتاج إلى إنشاء ملف PDF على جانب Android / iOS والذي يستغرق بعض الوقت وتؤدي طريقة الحساب (...) إلى تعطل التطبيق إذا قمت بتشغيل مكالمة من هناك.

حصلت على هذه المشكلة ، والآن أنا عالق.

أرغب في قراءة accessToken ، من التفضيلات المشتركة ، في الخلفية المعزولة ، على الرغم من أن التطبيق ليس في المقدمة (قد لا يكون العنصر الرئيسي قيد التشغيل ، لست متأكدًا تمامًا).

لذا ، هل يمكن لأي شخص أن يخبرني بحل لقراءة البيانات المستمرة من الخلفية المعزولة.
أنا حقا في مشكلة الآن.

/ ccbkonyi يبدو أن هذا مرتبط بشيء ما تعمل عليه.

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

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

لدي نفس المشكلة ، أعتقد أنها مهمة

قام أحد حل هذه المشكلة؟

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

لدي افتراض أنه عند تشغيل عزل من dart ، فإن المكتبات الأصلية لا ترتبط.

على سبيل المثال ، عند تشغيل شفرة flutter من جافا ، تُسمى هذه الطريقة:

   private native void nativeRunBundleAndSnapshotFromLibrary (
       long nativePlatformViewId,
       <strong i="7">@NonNull</strong> String [] prioritizedBundlePaths,
       <strong i="8">@Nullable</strong> String entrypointFunctionName,
       <strong i="9">@Nullable</strong> String pathToEntrypointFunction,
       <strong i="10">@NonNull</strong> AssetManager manager
   );

حيث يحدث كل السحر)

يتم التحقق من ذلك من خلال حقيقة أنه إذا قمت بإنشاء العديد من FlutterNativeView ، وفي كل تشغيل:

  public void runFromBundle (FlutterRunArguments args)

ثم نحصل على عدد قليل من "العزلة السامة"

نحن أيضا نواجه هذه القضية. نحتاج إلى جمع البيانات من عزل الخلفية (مثل الموقع والضوضاء وما إلى ذلك) والتي تعتمد جميعها على قنوات النظام الأساسي. @ mravn-google - هل هناك أي خبر عن تحديث لواجهة برمجة التطبيقات يمكنه معالجة هذا الأمر؟

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

لقد واجهت أيضًا مشكلة مماثلة وعلقت الآن.

+1 (يحتاج مشروعي أيضًا بشدة إلى قنوات النظام الأساسي بمعزل عن غيرها)

أنا بحاجة لتقديم الصور في الخلفية. يجب أن يتم ذلك بشكل منفصل لأن كل صورة تستغرق بضع ثوان وتحظر واجهة المستخدم إذا تم إجراؤها في السلسلة الرئيسية. أنا عالق عند أول مكالمة أصلية لـ dart: ui.PictureRecorder وأفترض أن كل مكالمة رسومية (التي تستخدم وظائف أصلية) لن تعمل أيضًا. نظرًا لأنني أستخدم الكثير من الوظائف في اللوحة القماشية ، فسيكون من الصعب العمل مع منافذ رد الاتصال.

حل محل تقدير كبير.

+1 حصلت على هذه المشكلة

يبدو أن @ mravn-google قد توقف عن العمل لدى Google في آرهوس. أتساءل عما إذا كان هناك أي شخص آخر من فريق Google Flutter يبحث في هذا الأمر. IMO ، هذا هو سدادة عرض رئيسية للاستخدام الجاد لـ Flutter لبناء تطبيقات Flutter مرنة وقوية ...

ربما يمكن أن تعطي sethladd مكانة؟

+1

أي تحديثات على هذا؟

+1

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

نحتاج إلى شرح أكثر تفصيلاً للحل البديل لمستخدمي flutter / dart الجدد. لقد بدأت فقط في استخدام العزلات منذ يومين ، والرفرفة / النبال الأسبوع الماضي ، ويبدو أنني سأضطر إلى استخدام الخيط الرئيسي لبعض المهام التي تتطلب جهدًا كبيرًا ، مما يجعل التعلم من الرفرفة حلاً سيئًا. بدون تعدد مؤشرات الترابط القابل للاستخدام ، من الأفضل أن أتعلم لغة Kotlin وأنشئ تطبيقاتي مرتين. آمل أن تتمكنوا جميعًا من الحصول على شيء مفهوم للمبتدئين معًا ، أود حقًا أن أكون قادرًا على تبرير رفرفة التعلم لأصحاب العمل حتى أتمكن من استخدامه في العمل.
إذا لم يكن هنا ، ربما على StackOverflow ، لقد قمت بنشر سؤال هنا: https://stackoverflow.com/q/57466952/6047611

+1 آمل أن يتم إصلاحه قريبًا

+1 يحتاج مشروعي إلى قنوات منفصلة.

واجهت نفس المشكلة وقمت بعمل حزمة ( Isolate Handler ) باستخدام حل بديل مشابه لتلك التي نشرتها @ mravn-google. ومع ذلك ، يسمح لك Isolate Handler باستخدام قنوات من العزل الرئيسي جنبًا إلى جنب مع العزلات الأخرى. وهو يدعم مكالمات MethodChannel المباشرة من داخل العزلات ، لكن التدفقات الحالية EventChannel غير مدعومة. سأبحث في إضافة الدعم لهم إذا اتضح أنه شيء يحتاجه الناس.

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

هناك خيار آخر تم نشره أعلاه وهو FlutterIsolate ، والذي يستخدم أسلوبًا مختلفًا ويستحق النظر فيه أيضًا.

نأمل أن توفر مطوري Flutter حلاً كاملاً ومناسبًا لهذه المشكلة قريبًا.

تعديل:

لقد قمت في النهاية بحل مشكلتي بشكل أكثر وضوحًا من خلال بدء العزلة عن الجانب الأصلي بدلاً من استخدام نهج مشابه للمكوِّن الإضافي لـ Flutter الخاص بـ Android Alarm Manager .

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

+1 أي تحديث هنا؟

+1

شيء مثير للاهتمام ألاحظه هنا:
يبدو أن العديد من الإضافات قد تمت كتابتها بافتراض أن استدعاء قناة الطريقة يقوم بتمرير الرسائل من Dart إلى سلسلة رسائل في الخلفية ؛ بشكل مرتبط ، هناك بعض الأشخاص المرتبكين بشدة الذين اتبعوا مثال bg geofencing ويتساءلون الآن عن كيفية العودة إلى الموضوع الرئيسي ...
لن يتسبب رمز المكون الإضافي هذا في حدوث "jank" إذا كانوا يؤدون مهمة قصيرة ، ولكن يتم تشغيلهم افتراضيًا على مؤشر ترابط النظام الأساسي ، وهو ما كان يطلق عليه "مؤشر ترابط واجهة المستخدم" على android ؛ يمكن أن يتسبب هذا تمامًا في إسقاط الإيماءات أثناء عبء العمل الكبير ، وأنا أفهم أنه سيؤدي إلى حظر جميع قنوات الرسائل الأخرى أيضًا.
أنت بعد ذلك تحت رحمة هندسة مؤلف البرنامج المساعد ؛ فقط إذا قاموا بنقل عملهم الثقيل إلى مؤشر ترابط آخر في الكود الأصلي ، فستقوم بتشغيل الكود الذي ينتظر قنوات الطريقة ؛ يجب أن تعمل قنوات الرسائل هذه على مؤشر ترابط النظام الأساسي.
بينما أفهم الأساس المنطقي الذي يشير إليه chinmaygarde الجيد هنا ، متفقًا على ما يلي:

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

    • لا يمكنني إلا أن أتخيل كيف يمكن أن يتضاعف ذلك عند إجراء أول مكالمات واجهة برمجة تطبيقات النظام الأساسي فقط.

أشعر أن البنية الناتجة قد فتحت نمطًا مضادًا كبيرًا كإعداد افتراضي لمؤلفي الإضافات ؛ للوهلة الأولى ، أعتقد أنه حتى المكوّن الإضافي firebase ml يستخدم مؤشر ترابط النظام الأساسي لمعالجته.
لذلك أتمنى أن يكون هناك نوع من التحذير القوي الذي من شأنه أن يعطى للأشخاص الذين يقومون برفع الأحمال الثقيلة ؛ ربما يكون هناك شيء ما في التطبيق النموذجي الافتراضي يولد أخطاء على الشاشة إذا استغرقت مكالمات قناة الرسائل وقتًا أطول من 20 مللي ثانية تقريبًا للعودة ، ربما شيء أكثر في وجه الجميع ؛ بصراحة ، كل ما يقنع هؤلاء الأشخاص بإجراء مكالمات db & c. للذهاب الحصول على موضوع بالفعل.

أوي ، ليس هناك غداء مجاني ، هذا أمر مؤكد ...

انتهى بي الأمر إلى تنفيذ عبء عمل ثقيل باستخدام خيوط المنصة الأصلية باستخدام Java و Swift. لم يتم العثور على حل بديل.

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

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

+1 بحاجة إلى هذا

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

+1 بحاجة إلى هذا

+1

أحتاج إلى استدعاء طريقة قناة النظام الأساسي من عزل آخر أيضًا!

+1

+1

+1

+1 هذا أمر لا بد منه

+1
لدي SDK أصلي يجب أن أتصل به. سيكون من الجيد أن يكون لديك شيء مثل BackgroundFlutterMethodChannel .

+1

+1

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

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

+1

+1

+1

+1

+1 بحاجة إلى هذا

+1 بحاجة إلى هذا أيضًا!

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

  • لاستدعاء واجهات برمجة التطبيقات الخاصة بالمنصة
  • لتشغيل المهام الثقيلة الخاصة بالنظام الأساسي في الخلفية والإبلاغ عند الانتهاء

وهذا مانع رئيسي.

يتعامل المكون الإضافي flutter_downloader مع كود عزل الخلفية. أعتقد أن الأمر يستحق النظر إليه.

كنت آمل أن يتم حل هذا في الإصدار القادم ، لكن الخطأ لا يزال في الإصدار 1.12!

الكود الخاص بالعميل موجود بشكل كبير على الجانب الآخر من القناة ومكتوب بلغة kotlin والتطبيق تقريبًا ثابت لكل اتصال http فردي

Gooooooooooooooogle؟ !!!!!!!!!!!!؟!؟!؟!؟

قد يكون هذا البرنامج المساعد مفيدًا flutter_isolate

+1 نحن بحاجة إلى هذا ... هيا

+1

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

+1 بحاجة إلى هذا

كتابة كود مرهق لبيانات الصفحة.

lukaszciastko ماذا تقصد بكتابة التعليمات البرمجية لبيانات الصفحة. هل هناك طريقة لحل تأخر واجهة المستخدم عند إرسال أجزاء كبيرة من البيانات ؟؟

تضمين التغريدة

اعتمادًا على مدى تعقيد ما تقوم به ISOLATE والتواصل بين واجهة المستخدم و ISOLATE - من الممكن حل هذه المشكلة في كود واجهة المستخدم الخاصة بك عن طريق هيكلة البيانات التي تتطلبها ISOLATE للقيام بعملها مسبقًا قبل استدعاء ISOLATE. لدي نسخة غنية من ملفات PDF في تطبيق Flutter الحالي - يمكن للمستخدم تحديد عدة ملفات PDF لإنشاءها.

يمكن لكل منها إنشاء من 1 إلى 10000 صفحة. واجهة المستخدم الخاصة بي تستجيب ، عندما تكتمل كل مهمة ، يتم إنشاء TAB لعرض التقرير - يتم إخطار المستخدم عند اكتمال المهمة عبر TOAST ولا تتوقف واجهة المستخدم عن التوقف - لا يدرك المستخدم أن هناك خدمات في الخلفية مشغولة توليد ملفات PDF غنية.

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

MsXam لكن لا يمكنني استدعاء وظيفة خاصة بالمنصة من عزل آخر ... مما يجعلني أستدعي الوظيفة الخاصة بالنظام الأساسي في العزل الرئيسي ... مما يؤدي إلى واجهة مستخدم متخلفة

لدي نفس المشكلة ، أعتقد أنها مهمة للغاية

تضمين التغريدة

اعتمادًا على مدى تعقيد ما تقوم به ISOLATE والتواصل بين واجهة المستخدم و ISOLATE - من الممكن حل هذه المشكلة في كود واجهة المستخدم الخاصة بك عن طريق هيكلة البيانات التي تتطلبها ISOLATE للقيام بعملها مسبقًا قبل استدعاء ISOLATE. لدي نسخة غنية من ملفات PDF في تطبيق Flutter الحالي - يمكن للمستخدم تحديد عدة ملفات PDF لإنشاءها.

يمكن لكل منها إنشاء من 1 إلى 10000 صفحة. واجهة المستخدم الخاصة بي تستجيب ، عندما تكتمل كل مهمة ، يتم إنشاء TAB لعرض التقرير - يتم إخطار المستخدم عند اكتمال المهمة عبر TOAST ولا تتوقف واجهة المستخدم عن التوقف - لا يدرك المستخدم أن هناك خدمات في الخلفية مشغولة توليد ملفات PDF غنية.

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

هل تتصل برمز خاص بالمنصة؟

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

أنا عالق في نفس الشيء.

أقوم باستدعاء قناة methodchannel برمز kotlin و getStream.io API ، لكن هذا بطيء للغاية ، وتجميد Flutter UI الخاص بي ، كنت أرغب في إضافة حساب إليها ، لكنني حصلت على نفس الأخطاء.

كيف يمكنني اصلاح هذا؟

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

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

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

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

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

لقد تعلمت الرفرفة لمدة 10 أيام ، وأحبها حتى الآن ، ولكن بعد فترة من التجربة ، بدأت في مواجهة المشاكل ، ورؤية الجوانب السلبية ، وهذه المشكلة ، تم فتحها منذ 5 يناير 2018 ، ...

الرجاء إصلاح هذا الخطأ.

نأمل في الدعم قريبا.

jpsarda ، @ klaszlo8207 لا تحبس أنفاسك. ونعم ، * كان هناك حل للمشكلة ، حتى اليوم: https://pub.dev/packages/isolate_handler. اضطر المبرمج إلى سحب القابس عليه اليوم لأن التغيير الأخير في Flutter (قبل أيام قليلة فقط) جعل من المستحيل اتباع هذا المسار بعد الآن.

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

سيكون من الجيد أن يكون لديك سهم يتعامل مع تعدد مؤشرات الترابط افتراضيًا في أي وقت تستخدم فيه وظيفة غير متزامنة.

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

zoechi نود معرفة ما إذا كان هناك أي تحديث لهذه المشكلة أو ما إذا كانت هناك أي خطة لإصلاحها؟
شكرا لك.

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

  • يوفر https://pub.dev/packages/flutter_isolate عزلًا بديلاً يمكنه التواصل مع المكونات الإضافية لأنه ينشئ دعم واجهة المستخدم الخاصة به (لا شيء تراه أو يتعين عليك التعامل معه ، فقط تقنيًا) ،

  • https://pub.dev/packages/isolate_handler الذي قمنا بتعديله للتو للاعتماد على الحزمة أعلاه لأن الطريقة السابقة التي استخدمتها كانت مستحيلة بسبب تغيير Flutter الأخير. الميزة في استخدام هذه الحزمة بدلاً من flutter_isolate نفسها هي أن هذا يضيف إمكانيات معالجة ، يمكنك بدء عدة عزلات ، وتتبعها ولا يتعين عليك إعداد اتصالك الخاص بين المعزول والرئيسي مؤشر ترابط (شيء عليك القيام به يدويًا مع كل من المخزون الأصلي Isolate و FlutterIsolate ) لأنه تم تجريده بعيدًا ومتاحًا بسهولة.

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

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

مرحبًا deakjahn ، شكرًا لك على إجابتك السريعة.

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

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

أحاول تشغيل مثال getBatteryLevel:
https://flutter.dev/docs/development/platform-integration/platform-channels؟tab=android-channel-java-tab
ويتعطل في كل مرة أحاول تشغيله على جهاز android. هل يمكن لاحد المساعدة رجاءا؟ لست متأكدًا حتى من كيفية التحقق من الخطأ ، نظرًا لعدم وجود سجلات ويستمر تشغيله في حلقة لا نهائية وأنا أستخدم نفس الرمز بالضبط.

تسمية هذه المشكلة لـ P5 ؟؟؟ 🥵

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

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

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

أيضًا ، قرأت جميع تعليقاتك وأشعر وكأنك تروج فقط للحزمة التي أنشأتها.

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

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

شكرًا deakjahn على هذه النصائح ، هل سيساعدني استخدام طريقة العزلة المعزولة في استدعاء طريقة وإرسال البيانات إلى جانب السهام كلما تلقيت إشعارًا من الجانب الأصلي؟ (أنا أستخدم sdks الأصلي لـ twilio وأتلقى إشعارات الدفع على الجانب الأصلي)

إذا كان هذا يعني أن لديك مكونًا إضافيًا patform تستخدمه للتواصل من خلال قناة النظام الأساسي ، فعندئذٍ ، نعم ، ستساعدك أي من الحزمتين. إذا كانت تعمل من كود عادي ، فإن هذه الحزم ستجعلها تعمل من عزل أيضًا.

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

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

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

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

لقد أضفت طريقة للخروج من هذا ، في نافذة تنبيه نظام المكون الإضافي الخاص بي

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

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

لذلك على سبيل المثال ، إذا كنت ترغب في فعل أي شيء باستخدام التفضيلات المشتركة في backgroundMessageHandler لمكوِّن FCM الإضافي عند إغلاق التطبيق ، فسيتم طرح MissingPluginException.

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

وربما يكون هناك العديد من السيناريوهات الأخرى حيث تمثل هذه مشكلة كبيرة.

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

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

ryanheise حتى flutter_isolate هل هذا بالنسبة لي؟ كيف لا يمكنني معرفة ذلك من المستندات. ما الذي يجب علي فعله لجعله يعمل مع FCM onBackgroundMessage الخاص بي؟ لذا أحتاج إلى إنتاج عزل جديد في onBackgroundMessageHandler الخاص بي؟ لكن لا يمكنني استخدام المكونات الإضافية هناك ، فكيف يمكنني استخدام flutter_isolate بعد ذلك؟

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

أنا في حاجة ماسة للمساعدة في هذا. هل من الممكن بأي طريقة القيام بذلك. لدي أول يوم تداول جدي ولا يمكنني معرفة ذلك.

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

أقوم بإعداد Application.kt الخاص بي مثل هذا

import `in`.jvapps.system_alert_window.SystemAlertWindowPlugin
import io.flutter.app.FlutterApplication
import io.flutter.plugin.common.PluginRegistry
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback
import io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService

import android.os.Build
import android.app.NotificationManager
import android.app.NotificationChannel

public class Application: FlutterApplication(), PluginRegistrantCallback {

   override fun onCreate() {
     super.onCreate()
     FlutterFirebaseMessagingService.setPluginRegistrant(this)
     createNotificationChannels()
     SystemAlertWindowPlugin.setPluginRegistrant(this)
   }

   override fun registerWith(registry: PluginRegistry) {
     FirebaseCloudMessagingPluginRegistrant.registerWith(registry)
     SystemAlertWindowPlugin.registerWith(registry.registrarFor("in.jvapps.system_alert_window"))
   }

   fun createNotificationChannels() {
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val name = "groupChannel"
        val descriptionText = "This is the group channel"
        val importance = NotificationManager.IMPORTANCE_HIGH
        val mChannel = NotificationChannel("59054", name, importance)
        mChannel.description = descriptionText
        val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.createNotificationChannel(mChannel)
    }
  }
}

من الأفضل نشر هذا على صفحة مشكلات firebase_messaging لأنه لا علاقة لها بهذه المشكلة.

يمكنني إنشاء علاقات عامة ، والتي سيكون لها طريقة "spawnIsolate" جديدة لـ "SchedulerBinding".

بعد ذلك سيكون من الممكن استدعاء طرق النظام الأساسي في هذه العزلة.

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

import 'dart:async';
import 'dart:isolate';

import 'package:flutter/scheduler.dart';
import 'package:flutter/widgets.dart';
import 'package:path_provider/path_provider.dart';

Future<void> _test(SendPort sendPort) async {
  final dir = await getTemporaryDirectory();
  sendPort.send(dir);
}

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  final Completer<Object> completer = Completer<Object>();
  final RawReceivePort receivePort = RawReceivePort(completer.complete);

  final Isolate isolate = await ServicesBinding.instance.spawnIsolate(
    _test,
    receivePort.sendPort,
  );

  print(await completer.future);

  receivePort.close();
  isolate.kill();
}

سجل

Performing hot restart...
Syncing files to device Pixel 4...
Restarted application in 722ms.
I/flutter (11705): Directory: '/data/user/0/com.example.bug/cache'

يمكنني إنشاء علاقات عامة ، والتي سيكون لها طريقة "spawnIsolate" جديدة لـ "SchedulerBinding".

بعد ذلك سيكون من الممكن استدعاء طرق النظام الأساسي في هذه العزلة.

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

SchedulerBinding.instance.spawnIsolate

أي فرصة لاختبار هذا؟ إذا كان يناسب احتياجاتي وما إلى ذلك ..

تضمين التغريدة
استبدل هذا الملف (الفعلي للإصدار 1.17.5)


تجليد

"" dart // حقوق الطبع والنشر 2014 The Flutter Authors. كل الحقوق محفوظة.
// استخدام كود المصدر هذا محكوم بترخيص من طراز BSD يمكن أن يكون
// موجود في ملف الترخيص.

استيراد " dart: غير متزامن " ؛
استيراد " dart: عزل " ؛
استيراد " dart: typed_data " ؛
استيراد " dart: ui " مثل واجهة المستخدم ؛

استيراد " الحزمة: رفرفة / Foundation.dart " ؛

استيراد "asset_bundle.dart" ؛
استيراد "binary_messenger.dart" ؛
استيراد "system_channels.dart" ؛

/// يستمع إلى رسائل النظام الأساسي ويوجهها إلى [defaultBinaryMessenger].
///
/// تسجل [ServicesBinding] أيضًا [LicenseEntryCollector] التي تكشف
/// التراخيص الموجودة في الملف LICENSE المخزن في جذر الأصل
/// bundle ، وتنفذ ملحق الخدمة ext.flutter.evict (انظر
/// [إخلاء]).
خدمات mixinBinding on BindingBase {
@تجاوز
initInstances باطلة () {
super.initInstances () ؛
_instance = هذا ؛
_defaultBinaryMessenger = createBinaryMessenger () ،
window.onPlatformMessage = defaultBinaryMessenger.handlePlatformMessage ؛
initLicenses () ؛
SystemChannels.system.setMessageHandler (handleSystemMessage) ؛
}

/// [ServicesBinding] الحالية ، إذا تم إنشاؤها.
static ServicesBinding الحصول على مثيل => _instance ؛
خدمات ثابتة

/// المثيل الافتراضي لـ [BinaryMessenger].
///
/// يستخدم هذا لإرسال رسائل من التطبيق إلى النظام الأساسي ، و
/// يتتبع المعالجات التي تم تسجيلها على كل قناة
/// قد يرسل الرسائل الواردة إلى المعالج المسجل.
BinaryMessenger get defaultBinaryMessenger => _defaultBinaryMessenger ؛
BinaryMessenger _defaultBinaryMessenger ؛

/// ينشئ مثيل [BinaryMessenger] افتراضي يمكن استخدامه للإرسال
/// منصة الرسائل.
@محمي
BinaryMessenger createBinaryMessenger () {
إرجاع const _DefaultBinaryMessenger ._ () ،
}

/// تم استدعاء المعالج للرسائل المستلمة على [SystemChannels.system]
/// قناة الرسالة.
///
/// قد تتجاوز الارتباطات الأخرى هذا للرد على رسائل النظام الواردة.
@محمي
تضمين التغريدة
مستقبلhandleSystemMessage (كائن systemMessage) غير متزامن {}

/// يضيف التراخيص ذات الصلة إلى [LicenseRegistry].
///
/// بشكل افتراضي ، يضيف تنفيذ [ServicesBinding] لـ [initLicenses]
/// جميع التراخيص التي تم جمعها بواسطة أداة flutter أثناء التجميع.
@محمي
تضمين التغريدة
initLicenses باطلة () {
LicenseRegistry.addLicense (_addLicenses) ؛
}

تدفق_addLicenses () غير متزامنة * {
// نستخدم مؤقتات هنا (بدلاً من ScheduleTask من برنامج الربط)
// لأن طبقة الخدمات لا يمكنها استخدام رابط المجدول (المجدول
// يستخدم الربط طبقة الخدمات لإدارة أحداث دورة حياتها). الموقتات
// هي ما يستخدمه ScheduleTask على أي حال. الاختلاف الوحيد
// أن هذه ستعمل بعد ذلك فقط ، بدلاً من أن تكون ذات أولوية بالنسبة إلى
// المهام الأخرى التي قد تكون قيد التشغيل. باستخدام _something_ هنا للكسر
// هذا إلى جزأين مهم لأن العزلات تستغرق بعض الوقت لنسخها
// data في الوقت الحالي ، وإذا تلقينا البيانات في نفس حلقة الحدث
// التكرار بينما نرسل البيانات إلى المعزول التالي ، نحن بالتأكيد
// سوف تفوت الإطارات. الحل الآخر هو الحصول على العمل كله
// يحدث في عزلة واحدة ، وقد نذهب إلى هناك في النهاية ، لكننا أولاً
// سوف نرى ما إذا كان يمكن جعل الاتصال المعزول أرخص.
// انظر: https://github.com/dart-lang/sdk/issues/31959
// https://github.com/dart-lang/sdk/issues/31960
// TODO (ianh): قم بإزالة هذا التعقيد بمجرد إصلاح هذه الأخطاء.
المكمل النهائيrawLicenses = Completer() ؛
Timer.run (() غير متزامن {
rawLicenses.complete (rootBundle.loadString ('LICENSE'، cache: false)) ؛
}) ؛
في انتظار rawLicenses.future ؛
المكمل النهائي> parsedLicenses = Complete> () ؛
Timer.run (() غير متزامن {
parsedLicenses.complete (compute (_parseLicenses، await rawLicenses.future، debugLabel: 'parseLicenses')) ؛
}) ؛
انتظار تحليل التراخيص.
العائد * تيار.fromIterable (انتظار parsedLicenses.future) ؛
}

// يتم تشغيل هذا في عزل آخر تم إنشاؤه بواسطة _addLicenses أعلاه.
قائمة ثابتة_parseLicenses (String rawLicenses) {
السلسلة النهائية _licenseSeparator = '\ n' + ('-' * 80) + '\ n'؛
القائمة النهائيةالنتيجة =[] ؛
القائمة النهائيةالتراخيص = rawLicenses.split (_licenseSeparator) ؛
لـ (ترخيص السلسلة النهائية في التراخيص) {
انقسام int النهائي = License.indexOf ('\ n \ n') ؛
إذا (انقسام> = 0) {
result.add (LicenseEntryWithLineBreaks (
Licence.substring (0، split) .split ('\ n')،
الترخيص.سلسلة فرعية (انقسام + 2) ،
)) ؛
} آخر {
result.add (LicenseEntryWithLineBreaks (const[]، رخصة))؛
}
}
نتيجة العودة
}

@تجاوز
initServiceExtensions () باطلة {
super.initServiceExtensions () ،

assert(() {
  registerStringServiceExtension(
    // ext.flutter.evict value=foo.png will cause foo.png to be evicted from
    // the rootBundle cache and cause the entire image cache to be cleared.
    // This is used by hot reload mode to clear out the cache of resources
    // that have changed.
    name: 'evict',
    getter: () async => '',
    setter: (String value) async {
      evict(value);
    },
  );
  return true;
}());

}

/// تم الاتصال به استجابة لتمديد الخدمة ext.flutter.evict .
///
/// يتم استخدامه بواسطة الأداة flutter أثناء إعادة التحميل السريع بحيث يتم استخدام أي صور
/// التي تغيرت على القرص يتم مسحها من ذاكرات التخزين المؤقت.
@محمي
تضمين التغريدة
طرد باطل (مادة عرض سلسلة) {
rootBundle.evict (أصل) ؛
}

مستقبلتفرخ العزلة(
المستقبل أونقطة الدخول (رسالة T) ،
رسالة T ، {
منطقية متوقفة مؤقتًا = خطأ ،
أخطاء منطقية
SendPort onExit ،
SendPort onError ،
اسم تصحيح السلسلة ،
}) {
يجزم(
_isMainIsolate ،
"لا يمكن عمل مستويات متعددة من العزلات" ،
) ؛

final RawReceivePort messageReceiver = RawReceivePort(
  (Object receivedMessage) async {
    if (receivedMessage is SendPort) {
      receivedMessage.send(
        _IsolateStarter<T>(
          ui.PluginUtilities.getCallbackHandle(entryPoint),
          message,
        ),
      );
    } else if (receivedMessage is _Message) {
      final ByteData result = await defaultBinaryMessenger.send(
        receivedMessage.channel,
        receivedMessage.message,
      );
      receivedMessage.sendPort.send(result);
    }
  },
);
RawReceivePort onExitReceiver;
onExitReceiver = RawReceivePort(
  (Object message) {
    onExit?.send(message);

    onExitReceiver.close();
    messageReceiver.close();
  },
);

return Isolate.spawn(
  _startIsolate,
  messageReceiver.sendPort,
  paused: paused,
  errorsAreFatal: true,
  onExit: onExitReceiver.sendPort,
  onError: onError,
  debugName: debugName,
);

}
}

مستقبل_startIsolate(SendPort sendPort) غير متزامن {
_sendPortToMainIsolate = sendPort ،
_IsolateBinding () ؛

المكمل النهائي <_IsolateStarter> مكمل =
المكمل <_IsolateStarter> () ؛

استلام RawReceivePort النهائي = RawReceivePort (
(الكائن المعزول ستارتر) {
تأكيد (العزلة هي _IsolateStarter) ؛
Completeer.complete (يعزل Starter كـ _IsolateStarter) ؛
} ،
) ؛

sendPort.send (receivePort.sendPort) ،

نهائي _IsolateStarterالعزلة

ReceivingPort.close () ،

وظيفة الوظيفة النهائية =
ui.PluginUtilities.getCallbackFromHandle (العزلةStarter.callbackHandle) ؛

انتظار وظيفة (العزلةStarter.message) ؛
}

SendPort _sendPortToMainIsolate ،

bool get _isMainIsolate => _sendPortToMainIsolate == null ؛

فئة _IsolateStarter{
_IsolateStarter (this.callbackHandle ، this.message) ؛

واجهة المستخدم النهائية رد اتصال CallbackHandle ؛
رسالة T النهائية ؛
}

فئة _Message {
_رسالة(
هذه القناة ،
هذه الرسالة،
this.sendPort ،
) ؛

قناة السلسلة النهائية ؛
رسالة ByteData النهائية ؛
SendPort النهائي sendPort ؛
}

تمدد فئة _IsolateBinding BindingBase باستخدام ServicesBinding {}

/// التطبيق الافتراضي لـ [BinaryMessenger].
///
/// يرسل هذا برنامج المراسلة رسائل من جانب التطبيق إلى جانب النظام الأساسي و
/// يرسل الرسائل الواردة من جانب النظام الأساسي إلى الجهة المناسبة
/// معالج.
تمدد فئة _DefaultBinaryMessenger BinaryMessenger {
const _DefaultBinaryMessenger ._ () ،

// معالجات للرسائل الواردة من المكونات الإضافية للنظام الأساسي.
// هذا ثابت بحيث يمكن أن يكون لهذه الفئة مُنشئ ثابت.
ثابت الخريطة النهائية_ معالجات =
{} ؛

// معالجات وهمية تعترض الرسائل الصادرة وتستجيب لها.
// هذا ثابت بحيث يمكن أن يكون لهذه الفئة مُنشئ ثابت.
ثابت الخريطة النهائية_mockHandlers =
{} ؛

مستقبل_sendPlatformMessage (قناة String ، رسالة ByteData) {
المكمل النهائيمكمل = مكمل() ؛

if (_isMainIsolate) {
  // ui.window is accessed directly instead of using ServicesBinding.instance.window
  // because this method might be invoked before any binding is initialized.
  // This issue was reported in #27541. It is not ideal to statically access
  // ui.window because the Window may be dependency injected elsewhere with
  // a different instance. However, static access at this location seems to be
  // the least bad option.
  ui.window.sendPlatformMessage(channel, message, (ByteData reply) {
    try {
      completer.complete(reply);
    } catch (exception, stack) {
      FlutterError.reportError(FlutterErrorDetails(
        exception: exception,
        stack: stack,
        library: 'services library',
        context:
            ErrorDescription('during a platform message response callback'),
      ));
    }
  });
} else {
  RawReceivePort receivePort;
  receivePort = RawReceivePort(
    (Object message) async {
      assert(message is ByteData);
      completer.complete(message as ByteData);
      receivePort.close();
    },
  );
  _sendPortToMainIsolate.send(
    _Message(channel, message, receivePort.sendPort),
  );
}

return completer.future;

}

@تجاوز
مستقبلhandlePlatformMessage (
قناة سلسلة ،
بيانات بايتداتا ،
ui.PlatformMessageResponseCallback رد الاتصال ،
) غير متزامن {
استجابة بايتداتا ؛
يحاول {
معالج MessageHandler النهائي = _ المعالجات [القناة] ؛
إذا (معالج! = فارغ) {
استجابة = انتظار معالج (بيانات) ؛
} آخر {
ui.channelBuffers.push (قناة ، بيانات ، رد اتصال) ؛
رد الاتصال = لاغ ؛
}
} catch (استثناء ، مكدس) {
FlutterError.reportError (FlutterErrorDetails (
استثناء: استثناء ،
كومة: كومة ،
مكتبة: "مكتبة الخدمات" ،
السياق: ErrorDescription ('أثناء استدعاء رسالة النظام الأساسي') ،
)) ؛
} أخيرا {
إذا (رد الاتصال! = فارغ) {
رد الاتصال (استجابة) ؛
}
}
}

@تجاوز
مستقبلإرسال (قناة سلسلة ، رسالة ByteData) {
معالج MessageHandler النهائي = _mockHandlers [قناة] ؛
إذا (معالج! = فارغ)
معالج الإرجاع (رسالة) ؛
return _sendPlatformMessage (القناة ، الرسالة) ؛
}

@تجاوز
setMessageHandler باطلة (قناة سلسلة ، معالج MessageHandler) {
إذا (معالج == فارغ)
_handlers.remove (قناة) ؛
آخر
_ معالجات [قناة] = معالج ؛
ui.channelBuffers.drain (القناة ، (بيانات ByteData ، رد اتصال ui.PlatformMessageResponseCallback) غير متزامن {
في انتظار handlePlatformMessage (قناة ، بيانات ، رد اتصال) ؛
}) ؛
}

@تجاوز
setMockMessageHandler باطلة (قناة سلسلة ، معالج MessageHandler) {
إذا (معالج == فارغ)
_mockHandlers.remove (قناة) ؛
آخر
_mockHandlers [قناة] = معالج ؛
}
}
""

لدي flutter 1.21 لذا حاولت تحديث كل التعليمات البرمجية لتجميعها.
الآن هناك مشكلة واحدة متبقية لأن _ IsolateBinding يفتقد الكثير من تطبيقات أساليب BindingBase ...

أحصل على شيء مثل

Error: The non-abstract class '_IsolateBinding' is missing implementations for these members:
 - BindingBase with ServicesBinding.SchedulerBinding.addPersistentFrameCallback

حوالي 30 مرة.

في النهاية تطبع وحدة التحكم

/C:/flutter/packages/flutter/lib/src/services/binding.dart:341:7: Error: 'BindingBase' doesn't implement 'SchedulerBinding' so it can't be used with 'ServicesBinding'.
 - 'BindingBase' is from 'package:flutter/src/foundation/binding.dart' ('/C:/flutter/packages/flutter/lib/src/foundation/binding.dart').
 - 'SchedulerBinding' is from 'package:flutter/src/scheduler/binding.dart' ('/C:/flutter/packages/flutter/lib/src/scheduler/binding.dart').
 - 'ServicesBinding' is from 'package:flutter/src/services/binding.dart' ('/C:/flutter/packages/flutter/lib/src/services/binding.dart').
class _IsolateBinding extends BindingBase with ServicesBinding {}

لست متأكدًا بنسبة 100٪ مما يفعله استدعاء _IsolateBinding() في _startIsolate ولكن بدون ظهور الخطأ الشائع ServicesBinding.defaultBinaryMessenger was accessed before the binding was initialized. .

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


الملف الجديد يبدو مثل هذا (حتى الآن)

// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// <strong i="24">@dart</strong> = 2.8

import 'dart:async';
import 'dart:isolate';
import 'dart:typed_data';
import 'dart:ui' as ui;

import 'package:flutter/foundation.dart';
import 'package:flutter/scheduler.dart';

import 'asset_bundle.dart';
import 'binary_messenger.dart';
import 'restoration.dart';
import 'system_channels.dart';

/// Listens for platform messages and directs them to the [defaultBinaryMessenger].
///
/// The [ServicesBinding] also registers a [LicenseEntryCollector] that exposes
/// the licenses found in the `LICENSE` file stored at the root of the asset
/// bundle, and implements the `ext.flutter.evict` service extension (see
/// [evict]).
mixin ServicesBinding on BindingBase, SchedulerBinding {
  <strong i="25">@override</strong>
  void initInstances() {
    super.initInstances();
    _instance = this;
    _defaultBinaryMessenger = createBinaryMessenger();
    _restorationManager = createRestorationManager();
    window.onPlatformMessage = defaultBinaryMessenger.handlePlatformMessage;
    initLicenses();
    SystemChannels.system.setMessageHandler(handleSystemMessage);
    SystemChannels.lifecycle.setMessageHandler(_handleLifecycleMessage);
    readInitialLifecycleStateFromNativeWindow();
  }

  /// The current [ServicesBinding], if one has been created.
  static ServicesBinding get instance => _instance;
  static ServicesBinding _instance;

  /// The default instance of [BinaryMessenger].
  ///
  /// This is used to send messages from the application to the platform, and
  /// keeps track of which handlers have been registered on each channel so
  /// it may dispatch incoming messages to the registered handler.
  BinaryMessenger get defaultBinaryMessenger => _defaultBinaryMessenger;
  BinaryMessenger _defaultBinaryMessenger;

  /// Creates a default [BinaryMessenger] instance that can be used for sending
  /// platform messages.
  <strong i="26">@protected</strong>
  BinaryMessenger createBinaryMessenger() {
    return const _DefaultBinaryMessenger._();
  }

  /// Called when the operating system notifies the application of a memory
  /// pressure situation.
  ///
  /// This method exposes the `memoryPressure` notification from
  /// [SystemChannels.system].
  <strong i="27">@protected</strong>
  <strong i="28">@mustCallSuper</strong>
  void handleMemoryPressure() { }

  /// Handler called for messages received on the [SystemChannels.system]
  /// message channel.
  ///
  /// Other bindings may override this to respond to incoming system messages.
  <strong i="29">@protected</strong>
  <strong i="30">@mustCallSuper</strong>
  Future<void> handleSystemMessage(Object systemMessage) async {
    final Map<String, dynamic> message = systemMessage as Map<String, dynamic>;
    final String type = message['type'] as String;
    switch (type) {
      case 'memoryPressure':
        handleMemoryPressure();
        break;
    }
    return;
  }

  /// Adds relevant licenses to the [LicenseRegistry].
  ///
  /// By default, the [ServicesBinding]'s implementation of [initLicenses] adds
  /// all the licenses collected by the `flutter` tool during compilation.
  <strong i="31">@protected</strong>
  <strong i="32">@mustCallSuper</strong>
  void initLicenses() {
    LicenseRegistry.addLicense(_addLicenses);
  }

  Stream<LicenseEntry> _addLicenses() async* {
    // We use timers here (rather than scheduleTask from the scheduler binding)
    // because the services layer can't use the scheduler binding (the scheduler
    // binding uses the services layer to manage its lifecycle events). Timers
    // are what scheduleTask uses under the hood anyway. The only difference is
    // that these will just run next, instead of being prioritized relative to
    // the other tasks that might be running. Using _something_ here to break
    // this into two parts is important because isolates take a while to copy
    // data at the moment, and if we receive the data in the same event loop
    // iteration as we send the data to the next isolate, we are definitely
    // going to miss frames. Another solution would be to have the work all
    // happen in one isolate, and we may go there eventually, but first we are
    // going to see if isolate communication can be made cheaper.
    // See: https://github.com/dart-lang/sdk/issues/31959
    //      https://github.com/dart-lang/sdk/issues/31960
    // TODO(ianh): Remove this complexity once these bugs are fixed.
    final Completer<String> rawLicenses = Completer<String>();
    scheduleTask(() async {
      rawLicenses.complete(await rootBundle.loadString('NOTICES', cache: false));
    }, Priority.animation);
    await rawLicenses.future;
    final Completer<List<LicenseEntry>> parsedLicenses = Completer<List<LicenseEntry>>();
    scheduleTask(() async {
      parsedLicenses.complete(compute(_parseLicenses, await rawLicenses.future, debugLabel: 'parseLicenses'));
    }, Priority.animation);
    await parsedLicenses.future;
    yield* Stream<LicenseEntry>.fromIterable(await parsedLicenses.future);
  }

  // This is run in another isolate created by _addLicenses above.
  static List<LicenseEntry> _parseLicenses(String rawLicenses) {
    final String _licenseSeparator = '\n' + ('-' * 80) + '\n';
    final List<LicenseEntry> result = <LicenseEntry>[];
    final List<String> licenses = rawLicenses.split(_licenseSeparator);
    for (final String license in licenses) {
      final int split = license.indexOf('\n\n');
      if (split >= 0) {
        result.add(LicenseEntryWithLineBreaks(
          license.substring(0, split).split('\n'),
          license.substring(split + 2),
        ));
      } else {
        result.add(LicenseEntryWithLineBreaks(const <String>[], license));
      }
    }
    return result;
  }

  <strong i="33">@override</strong>
  void initServiceExtensions() {
    super.initServiceExtensions();

    assert(() {
      registerStringServiceExtension(
        // ext.flutter.evict value=foo.png will cause foo.png to be evicted from
        // the rootBundle cache and cause the entire image cache to be cleared.
        // This is used by hot reload mode to clear out the cache of resources
        // that have changed.
        name: 'evict',
        getter: () async => '',
        setter: (String value) async {
          evict(value);
        },
      );
      return true;
    }());
  }

  /// Called in response to the `ext.flutter.evict` service extension.
  ///
  /// This is used by the `flutter` tool during hot reload so that any images
  /// that have changed on disk get cleared from caches.
  <strong i="34">@protected</strong>
  <strong i="35">@mustCallSuper</strong>
  void evict(String asset) {
    rootBundle.evict(asset);
  }

  Future<Isolate> spawnIsolate<T>(
      FutureOr<void> entryPoint(T message),
      T message, {
        bool paused = false,
        bool errorsAreFatal,
        SendPort onExit,
        SendPort onError,
        String debugName,
      }) {
    assert(
    _isMainIsolate,
    'Can\'t make multiple levels of isolates',
    );

    final RawReceivePort messageReceiver = RawReceivePort(
          (Object receivedMessage) async {
        if (receivedMessage is SendPort) {
          receivedMessage.send(
            _IsolateStarter<T>(
              ui.PluginUtilities.getCallbackHandle(entryPoint),
              message,
            ),
          );
        } else if (receivedMessage is _Message) {
          final ByteData result = await defaultBinaryMessenger.send(
            receivedMessage.channel,
            receivedMessage.message,
          );
          receivedMessage.sendPort.send(result);
        }
      },
    );
    RawReceivePort onExitReceiver;
    onExitReceiver = RawReceivePort(
          (Object message) {
        onExit?.send(message);

        onExitReceiver.close();
        messageReceiver.close();
      },
    );

    return Isolate.spawn(
      _startIsolate,
      messageReceiver.sendPort,
      paused: paused,
      errorsAreFatal: true,
      onExit: onExitReceiver.sendPort,
      onError: onError,
      debugName: debugName,
    );
  }



  // App life cycle

  /// Initializes the [lifecycleState] with the [Window.initialLifecycleState]
  /// from the window.
  ///
  /// Once the [lifecycleState] is populated through any means (including this
  /// method), this method will do nothing. This is because the
  /// [Window.initialLifecycleState] may already be stale and it no longer makes
  /// sense to use the initial state at dart vm startup as the current state
  /// anymore.
  ///
  /// The latest state should be obtained by subscribing to
  /// [WidgetsBindingObserver.didChangeAppLifecycleState].
  <strong i="36">@protected</strong>
  void readInitialLifecycleStateFromNativeWindow() {
    if (lifecycleState != null) {
      return;
    }
    final AppLifecycleState state = _parseAppLifecycleMessage(window.initialLifecycleState);
    if (state != null) {
      handleAppLifecycleStateChanged(state);
    }
  }

  Future<String> _handleLifecycleMessage(String message) async {
    handleAppLifecycleStateChanged(_parseAppLifecycleMessage(message));
    return null;
  }

  static AppLifecycleState _parseAppLifecycleMessage(String message) {
    switch (message) {
      case 'AppLifecycleState.paused':
        return AppLifecycleState.paused;
      case 'AppLifecycleState.resumed':
        return AppLifecycleState.resumed;
      case 'AppLifecycleState.inactive':
        return AppLifecycleState.inactive;
      case 'AppLifecycleState.detached':
        return AppLifecycleState.detached;
    }
    return null;
  }

  /// The [RestorationManager] synchronizes the restoration data between
  /// engine and framework.
  ///
  /// See the docs for [RestorationManager] for a discussion of restoration
  /// state and how it is organized in Flutter.
  ///
  /// To use a different [RestorationManager] subclasses can override
  /// [createRestorationManager], which is called to create the instance
  /// returned by this getter.
  RestorationManager get restorationManager => _restorationManager;
  RestorationManager _restorationManager;

  /// Creates the [RestorationManager] instance available via
  /// [restorationManager].
  ///
  /// Can be overriden in subclasses to create a different [RestorationManager].
  <strong i="37">@protected</strong>
  RestorationManager createRestorationManager() {
    return RestorationManager();
  }
}

Future<void> _startIsolate<T>(SendPort sendPort) async {
  _sendPortToMainIsolate = sendPort;
  _IsolateBinding();

  final Completer<_IsolateStarter<T>> completer =
  Completer<_IsolateStarter<T>>();

  final RawReceivePort receivePort = RawReceivePort(
        (Object isolateStarter) {
      assert(isolateStarter is _IsolateStarter<T>);
      completer.complete(isolateStarter as _IsolateStarter<T>);
    },
  );

  sendPort.send(receivePort.sendPort);

  final _IsolateStarter<T> isolateStarter = await completer.future;

  receivePort.close();

  final Function function =
  ui.PluginUtilities.getCallbackFromHandle(isolateStarter.callbackHandle);

  await function(isolateStarter.message);
}

SendPort _sendPortToMainIsolate;

bool get _isMainIsolate => _sendPortToMainIsolate == null;

class _IsolateStarter<T> {
  _IsolateStarter(this.callbackHandle, this.message);

  final ui.CallbackHandle callbackHandle;
  final T message;
}

class _Message {
  _Message(
      this.channel,
      this.message,
      this.sendPort,
      );

  final String channel;
  final ByteData message;
  final SendPort sendPort;
}

//TODO not working
class _IsolateBinding extends BindingBase with ServicesBinding {}

/// The default implementation of [BinaryMessenger].
///
/// This messenger sends messages from the app-side to the platform-side and
/// dispatches incoming messages from the platform-side to the appropriate
/// handler.
class _DefaultBinaryMessenger extends BinaryMessenger {
  const _DefaultBinaryMessenger._();

  // Handlers for incoming messages from platform plugins.
  // This is static so that this class can have a const constructor.
  static final Map<String, MessageHandler> _handlers =
  <String, MessageHandler>{};

  // Mock handlers that intercept and respond to outgoing messages.
  // This is static so that this class can have a const constructor.
  static final Map<String, MessageHandler> _mockHandlers =
  <String, MessageHandler>{};

  Future<ByteData> _sendPlatformMessage(String channel, ByteData message) {
    final Completer<ByteData> completer = Completer<ByteData>();

    if (_isMainIsolate) {
      // ui.window is accessed directly instead of using ServicesBinding.instance.window
      // because this method might be invoked before any binding is initialized.
      // This issue was reported in #27541. It is not ideal to statically access
      // ui.window because the Window may be dependency injected elsewhere with
      // a different instance. However, static access at this location seems to be
      // the least bad option.
      ui.window.sendPlatformMessage(channel, message, (ByteData reply) {
        try {
          completer.complete(reply);
        } catch (exception, stack) {
          FlutterError.reportError(FlutterErrorDetails(
            exception: exception,
            stack: stack,
            library: 'services library',
            context:
            ErrorDescription('during a platform message response callback'),
          ));
        }
      });
    } else {
      RawReceivePort receivePort;
      receivePort = RawReceivePort(
            (Object message) async {
          assert(message is ByteData);
          completer.complete(message as ByteData);
          receivePort.close();
        },
      );
      _sendPortToMainIsolate.send(
        _Message(channel, message, receivePort.sendPort),
      );
    }

    return completer.future;
  }

  <strong i="38">@override</strong>
  Future<void> handlePlatformMessage(
      String channel,
      ByteData data,
      ui.PlatformMessageResponseCallback callback,
      ) async {
    ByteData response;
    try {
      final MessageHandler handler = _handlers[channel];
      if (handler != null) {
        response = await handler(data);
      } else {
        ui.channelBuffers.push(channel, data, callback);
        callback = null;
      }
    } catch (exception, stack) {
      FlutterError.reportError(FlutterErrorDetails(
        exception: exception,
        stack: stack,
        library: 'services library',
        context: ErrorDescription('during a platform message callback'),
      ));
    } finally {
      if (callback != null) {
        callback(response);
      }
    }
  }

  <strong i="39">@override</strong>
  Future<ByteData> send(String channel, ByteData message) {
    final MessageHandler handler = _mockHandlers[channel];
    if (handler != null)
      return handler(message);
    return _sendPlatformMessage(channel, message);
  }

  <strong i="40">@override</strong>
  void setMessageHandler(String channel, MessageHandler handler) {
    if (handler == null)
      _handlers.remove(channel);
    else
      _handlers[channel] = handler;
    ui.channelBuffers.drain(channel, (ByteData data, ui.PlatformMessageResponseCallback callback) async {
      await handlePlatformMessage(channel, data, callback);
    });
  }

  <strong i="41">@override</strong>
  void setMockMessageHandler(String channel, MessageHandler handler) {
    if (handler == null)
      _mockHandlers.remove(channel);
    else
      _mockHandlers[channel] = handler;
  }

  <strong i="42">@override</strong>
  bool checkMessageHandler(String channel, MessageHandler handler) => _handlers[channel] == handler;

  <strong i="43">@override</strong>
  bool checkMockMessageHandler(String channel, MessageHandler handler) => _mockHandlers[channel] == handler;
}

تضمين التغريدة
في الوقت الحالي ، لا يمكنني تحديث الرفرفة لمساعدتك

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

هذه ليست ميزة جديدة خطيرة ، إنها أداة حظر الإطارات.
لذلك وفقًا لهذا https://github.com/flutter/flutter/issues/18761#issuecomment -639248761 يجب أن يكون P3

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

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

لست متأكدًا أيضًا مما إذا كان بعض إجراءات 1+ لا يفهمون تمامًا موضوع المشكلة. (مثل https://github.com/flutter/flutter/issues/13937#issuecomment-635683123). Imo الوثائق الرسمية لعزل الخلفية ووقت التشغيل بلا رأس (وكيفية إدارته) لا تزال غير متوفرة بعض الشيء وعناصر المراسلة في Firebase كابوس ، لكن هذا لا علاقة له بالإطار ، المحرك 🤷‍♂️

ربما توقف عن ضرب فريق الرفرفة ، هناك تقدم مذهل ، وهذا ليس شيئًا لا يمكن حله ... وإذا كان هناك علاقات عامة ، فلماذا لا ترسلها لفريق الرفرفة للنظر 🤔

هناك مشكلة في تنفيذ هذا السلوك للعزلات.

مثال:

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

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

hpoul ، يجب أن أوافق على عدم الموافقة لأن العديد من الأشخاص هنا مبتدئين في برمجة android / ios وقد اختاروا إطار عملهم الأول لتطوير التطبيق ليكون مرفرفًا.

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

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

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

مرحبا phanirithvij

تم ربط flutter_isolate أعلاه وكان موجودًا منذ فبراير 2019. كما أنه ليس معقدًا. سوف أقوم بنسخ ملف README الذي يبدو واضحًا ومباشرًا:

يسمح FlutterIsolate بإنشاء Isolate in flutter قادرًا على استخدام ملحقات flutter. يقوم بإنشاء وحدات البت الضرورية الخاصة بالنظام الأساسي (FlutterBackgroundView على android و FlutterEngine على iOS) لتمكين قنوات النظام الأساسي من العمل داخل عزل.

| | أندرويد | iOS | الوصف |
| : --------------- | : ----------------: | : ------------------: | : -------------------------------- |
| FlutterIsolate.spawn (نقطة دخول ، رسالة) | : white_check_mark: | : white_check_mark: | يولد FlutterIsolate جديدًا |
| flutterIsolate.pause () | : white_check_mark: | : white_check_mark: | يوقف تشغيل عزل |
| flutterIsolate.resume () | : white_check_mark: | : white_check_mark: | استأنف isoalte المتوقف مؤقتًا |
| flutterIsolate.kill () | : white_check_mark: | : white_check_mark: | يقتل عزلة |

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

(ملاحظة: أنا أيضًا أرغب في إصلاح هذه المشكلة رسميًا للأسباب التي ذكرتها بالفعل في تعليق سابق ، والتي أشارككم في بعضها ، لكنني أيضًا لن أسمي هذا الحل البديل "معقدًا".)

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

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

تضمين التغريدة

يُنشئ flutter_isolate محركًا منفصلاً لكل عزل

لذلك أنا متأكد من أن فريق Flutter يمكنه القيام بعمل أفضل في ذلك أيضًا.

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

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

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

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

آسف ، لم ألاحظ أن هذه شوكة

يجب أن يقوم flutter_isolate بتدوير محرك كامل فقط للوصول إلى المكونات الإضافية.

إذا حددت أن "is_background_view = true" ، فلن يبدأ المحرك في العرض - مما يعني أن المحرك لا يبدأ تمامًا

تختلف واجهة برمجة التطبيقات الدقيقة للتشغيل بدون رأس بالنسبة لنظامي التشغيل iOS و Android v1 و Android v2 ، ولكن هذا هو ما يفعله flutter_isolate بالفعل. لا يزال هناك فرق في النفقات العامة بين العزلة العادية ومحرك FlutterEngine ، على الرغم من ذلك ، لذا فإن خفض النفقات العامة هو مجرد شيء يمكن لفريق Flutter القيام به. إنها ليست مجرد عبء في وقت بدء التشغيل ، بل إنها أيضًا زيادة في استخدام الذاكرة.

هل تقترح فقط تحسين إنشاء محرك جديد للعمل في الخلفية؟

ثم ربما لا ينطبق هذا على هذه المشكلة

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

إذا كان المحرك 1 ، والعزلات أكبر من 1 ، فإننا نعود إلى هذا السؤال:

https://github.com/flutter/flutter/issues/13937#issuecomment -667314232

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

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

إذا كنت تسألني

نعم أسأل

يمكن أن ترسل رسائل إلى حق عزل.

أعتقد أن هذا حل سيئ لأن "العزلة الصحيحة" مفهوم نسبي

قم بإنشاء سجل مكون إضافي وما إلى ذلك لكل عزل ولكن داخل نفس FlutterEngine ،

قد يكون هذا خيارًا جيدًا ، ولكن فقط إذا كان المحرك يسجل دائمًا المكونات الإضافية بنفسه.

لكن هذا يحدث فقط إذا كانت جميع المكونات الإضافية في GeneratedPluginRegistrant.
https://github.com/flutter/engine/blob/f7d241fd8a889fadf8ab3f9d57918be3d986b4be/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java#L330 -L344

إنشاء عمليات رد نداء إضافية ليس سلوكًا واضحًا.

أعتقد أن هذا حل سيئ لأن "العزلة الصحيحة" مفهوم نسبي

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

قد يكون هذا خيارًا جيدًا ، ولكن فقط إذا كان المحرك يسجل دائمًا المكونات الإضافية بنفسه.

وهو أمر جيد لضمان حدوثه دائمًا. حاليا الآلية غير مستقرة بعض الشيء.

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

ثم يجب أن يأخذ كل مكون إضافي في الاعتبار أنه يمكن الوصول إليه من عزلات مختلفة - سيئة

نعم.

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

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

بالطبع ، مع Dart يمكننا القيام بأكثر من مجرد واجهة مستخدم ، لكن دعونا لا ننسى الغرض الرئيسي لمجموعة الأدوات هذه.

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

إذا كان تطبيقك يحتاج حقًا إلى قوة المعالجة ، IMHO ، فلديك ثلاثة خيارات:

  • انقل منطقك إلى الخادم ؛
  • انقل منطقك إلى النظام الأساسي الأصلي - يمكنك استخدام Kotlin Native لهذا الغرض - واستخدم قنوات الأحداث / الطريقة لتوفير نماذج العرض لواجهة المستخدم الخاصة بك فقط (أعتقد أن هذا ما فعلته OLX: https://tech.olx.com/fast -النماذج الأولية-مع-رفرفة-kotlin-native-d7ce5cfeb5f1) ؛
  • لا تستخدم Flutter وابحث عن إطار عمل آخر (قد يكون Xamarin / Blazor مناسبًا لذلك حيث يوفر C # بيئة متعددة الخيوط أكثر تطوراً من Dart).

كل ما سبق له عيوبه ، لكن محاولة توسيع مكتبة / إطار عمل للقيام بما لم يتم تصميمه من أجله ليس مثاليًا أيضًا.

ألم يحل المتعامل المعزول هذه المشكلة

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

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

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

قم بإنشاء سجل مكون إضافي وما إلى ذلك لكل عزل ولكن داخل نفس FlutterEngine ،

قد يكون هذا خيارًا جيدًا ، ولكن فقط إذا كان المحرك يسجل دائمًا المكونات الإضافية بنفسه.

لكن هذا يحدث فقط إذا كانت جميع المكونات الإضافية في GeneratedPluginRegistrant.
https://github.com/flutter/engine/blob/f7d241fd8a889fadf8ab3f9d57918be3d986b4be/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java#L330 -L344

إنشاء عمليات رد نداء إضافية ليس سلوكًا واضحًا.

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

تضمين التغريدة

في المثال الخاص بك ، لا يتعلق الخطأ بهذه المشكلة

E/flutter ( 7814): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: Invalid argument(s): Isolate.spawn expects to be passed a static or top-level function

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

تضمين التغريدة


عينة التعليمات البرمجية

import 'package:battery/battery.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';

Future<void> main() async {
  await printBatteryLevel();
  await compute(printBatteryLevel, null);
}

Future<void> printBatteryLevel([dynamic message]) async {
  WidgetsFlutterBinding.ensureInitialized();
  print(await Battery().batteryLevel);
}



السجلات

Launching lib/main.dart on Pixel 4 in debug mode...
Running Gradle task 'assembleDebug'...
✓ Built build/app/outputs/flutter-apk/app-debug.apk.
Installing build/app/outputs/flutter-apk/app.apk...
Waiting for Pixel 4 to report its views...
Debug service listening on ws://127.0.0.1:50709/-SPs_6AmL2Q=/ws
Syncing files to device Pixel 4...
I/flutter ( 8708): 39
E/flutter ( 8708): [ERROR:flutter/lib/ui/ui_dart_state.cc(166)] Unhandled Exception: Exception: UI actions are only available on root isolate.
E/flutter ( 8708): #0      Window._nativeSetNeedsReportTimings (dart:ui/window.dart:1003:86)
E/flutter ( 8708): #1      Window.onReportTimings= (dart:ui/window.dart:996:29)
E/flutter ( 8708): #2      SchedulerBinding.addTimingsCallback (package:flutter/src/scheduler/binding.dart:272:14)
E/flutter ( 8708): #3      SchedulerBinding.initInstances (package:flutter/src/scheduler/binding.dart:209:7)
E/flutter ( 8708): #4      ServicesBinding.initInstances (package:flutter/src/services/binding.dart:27:11)
E/flutter ( 8708): #5      PaintingBinding.initInstances (package:flutter/src/painting/binding.dart:23:11)
E/flutter ( 8708): #6      SemanticsBinding.initInstances (package:flutter/src/semantics/binding.dart:24:11)
E/flutter ( 8708): #7      RendererBinding.initInstances (package:flutter/src/rendering/binding.dart:32:11)
E/flutter ( 8708): #8      WidgetsBinding.initInstances (package:flutter/src/widgets/binding.dart:257:11)
E/flutter ( 8708): #9      new BindingBase (package:flutter/src/foundation/binding.dart:59:5)
E/flutter ( 8708): #10     new _WidgetsFlutterBinding&BindingBase&GestureBinding (package:flutter/src/widgets/binding.dart)
E/flutter ( 8708): #11     new _WidgetsFlutterBinding&BindingBase&GestureBinding&SchedulerBinding (package:flutter/src/widgets/binding.dart)
E/flutter ( 8708): #12     new _WidgetsFlutterBinding&BindingBase&GestureBinding&SchedulerBinding&ServicesBinding (package:flutter/src/widgets/binding.dart)
E/flutter ( 8708): #13     new _WidgetsFlutterBinding&BindingBase&GestureBinding&SchedulerBinding&ServicesBinding&PaintingBinding (package:flutter/src/widgets/binding.dart)
E/flutter ( 8708): #14     new _WidgetsFlutterBinding&BindingBase&GestureBinding&SchedulerBinding&ServicesBinding&PaintingBinding&SemanticsBinding (package:flutter/src/widgets/binding.dart)
E/flutter ( 8708): #15     new _WidgetsFlutterBinding&BindingBase&GestureBinding&SchedulerBinding&ServicesBinding&PaintingBinding&SemanticsBinding&RendererBinding (package:flutter/src/widgets/binding.dart)
E/flutter ( 8708): #16     new _WidgetsFlutterBinding&BindingBase&GestureBinding&SchedulerBinding&ServicesBinding&PaintingBinding&SemanticsBinding&RendererBinding&WidgetsBinding (package:flutter/src/widgets/binding.dart)
E/flutter ( 8708): #17     new WidgetsFlutterBinding (package:flutter/src/widgets/binding.dart)
E/flutter ( 8708): #18     WidgetsFlutterBinding.ensureInitialized (package:flutter/src/widgets/binding.dart:1229:7)
E/flutter ( 8708): #19     printBatteryLevel (package:bug/main.dart:11:25)
E/flutter ( 8708): #20     _IsolateConfiguration.apply (package:flutter/src/foundation/_isolates_io.dart:83:34)
E/flutter ( 8708): #21     _spawn.<anonymous closure> (package:flutter/src/foundation/_isolates_io.dart:90:65)
E/flutter ( 8708): #22     Timeline.timeSync (dart:developer/timeline.dart:163:22)
E/flutter ( 8708): #23     _spawn (package:flutter/src/foundation/_isolates_io.dart:87:35)
E/flutter ( 8708): #24     _startIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:304:17)
E/flutter ( 8708): #25     _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:168:12)
E/flutter ( 8708): 



رفرفة الطبيب -v

[✓] Flutter (Channel stable, 1.20.4, on Mac OS X 10.15.6 19G2021, locale en-BY)
    • Flutter version 1.20.4 at /Users/nikitadold/development/flutter
    • Framework revision fba99f6cf9 (2 weeks ago), 2020-09-14 15:32:52 -0700
    • Engine revision d1bc06f032
    • Dart version 2.9.2

[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.0)
    • Android SDK at /Users/nikitadold/Library/Android/sdk
    • Platform android-30, build-tools 30.0.0
    • Java binary at: /Users/nikitadold/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/193.6626763/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 12.0.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 12.0.1, Build version 12A7300
    • CocoaPods version 1.9.3

[!] Android Studio (version 4.0)
    • Android Studio at /Users/nikitadold/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/193.6626763/Android Studio.app/Contents
    ✗ Flutter plugin not installed; this adds Flutter specific functionality.
    ✗ Dart plugin not installed; this adds Dart specific functionality.
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)

[✓] IntelliJ IDEA Ultimate Edition (version 2020.2.2)
    • IntelliJ at /Users/nikitadold/Applications/JetBrains Toolbox/IntelliJ IDEA Ultimate.app
    • Flutter plugin installed
    • Dart plugin version 202.7319.5

تضمين التغريدة
يرجى الاطلاع على هذا التعليق

يتم دعم رسائل النظام الأساسي فقط من العزل الرئيسي. [...]

هذا السلوك _ متوقع_ وله التصنيف severe: new feature
يجب اعتبار هذه المشكلة على أنها _طلب ميزة_ أو _ مقترح _ وليست _ خطأ_

تضمين التغريدة

في المثال الخاص بك ، لا يتعلق الخطأ بهذه المشكلة

E/flutter (23174): [ERROR:flutter/lib/ui/ui_dart_state.cc(166)] Unhandled Exception: Invalid argument(s): Illegal argument in isolate message : (object is a closure - Function '<anonymous closure>':.)

تضمين التغريدة

في المثال الخاص بك ، لا يتعلق الخطأ بهذه المشكلة

E/flutter (23174): [ERROR:flutter/lib/ui/ui_dart_state.cc(166)] Unhandled Exception: Invalid argument(s): Illegal argument in isolate message : (object is a closure - Function '<anonymous closure>':.)

أنت محق لي ليس مثالًا جيدًا ، يرجى تجاهله

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات