С выпуском Flutter 3.29 был сделан «важный» шаг: начиная с версии 3.29, Flutter на Android и iOS будет выполнять Dart-код на главном потоке приложения, и больше не будет отдельного потока Dart UI
Может быть, некоторые люди еще не знакомы с этим понятием, поэтому стоит обратиться к ранее опубликованному материалу «Глубокое понимание механизма асинхронной реализации Dart», где рассматривается связь между isolate, thread и runner.
Кратко говоря:
main
работает внутри корневого isolate, который является также основным потоком Dart-кода.На устройствах Android и iOS раньше создавались отдельные потоки для UI, GPU и IO, где UI Task Runner совпадал с корневым isolate Dart, то есть с основным потоком Dart-кода, а Platform Runner представлял собой главный поток платформы устройства.Поэтому в прошлом UI Runner и Platform Runner находились в разных потоках: Dart-корневой isolate был связан с UI Task Runner.
Из-за этого существовали асинхронные platform channels в Flutter, поскольку UI Runner и Platform Runner были разделены на разные потоки, что требовало сериализации и асинхронной передачи сообщений при взаимодействии Dart и Native.
Начиная с версии 3.29, как часть улучшений взаимодействия Native и Dart на мобильных платформах, два этих потока были объединены, другими словами, UI Runner = Platform Runner
.
Да, по умолчанию теперь merged_platform_ui_thread
установлен в true
, то есть UI Runner теперь равен Platform Runner, следовательно, Dart-корневой isolate связан с Platform Runner. Кроме того, раньше связывание корневого изолята Dart с UI Runner происходило при вызове SetMessageHandlingTaskRunner
, а теперь происходит непосредственно через post_directly_to_runner
:
Почему же можно так просто переключиться? На самом деле, это то, что мы уже обсуждали ранее — движок Engine не заботится о том, в каком потоке выполняется Runner; для Flutter Engine важно лишь то, чтобы задачи могли быть отправлены в Runner, и чтобы они были выполнены где-то.
Для Dart внутренний VM использует пулы потоков, такие как dart::ThreadPool
, для управления системными потоками, и код строится вокруг концепции dart::ThreadPool::Task
, а не вокруг конкретных системных потоков:> Например, дефолтная реализация цикла событий для обработки сообщений изолятов фактически не имеет отдельного потока событий; вместо этого dart::MessageHandlerTask
публикуется в пуле потоков при появлении нового сообщения.
Также, поскольку ранее потоки UI и Platform были разделены, все UI Runner использовали отдельные MessageLoopTaskQueues
для обработки микрозадач, но после объединения потоков UI Runner превратился в Platform Runner, и естественно, нет больше связанной очереди задач, поэтому требуется ручное обновление микрозадач после выполнения задачи.
Микрозадача представляет собой тип задач изолятов с более высоким приоритетом.
Кроме того, большинство операций PostTask
стали RunNowOrPostTask
, основанными на проверках состояния инициализации MessageLoop
для выбора места выполнения:
Здесь также стоит обратить внимание на логику инициализации платформенного Runner при слиянии двух потоков, которая показывает, что MessageLoop
не будет пустым, следовательно, IsInitializedForCurrentThread
будет истинным, то есть задача task()
будет выполнена непосредственно в текущем потоке:
Аналогично на iOS используется текущий MessageLoop
:
> В действительности, после объединения потоков отдельный поток буферизации Flutter остаётся таким, каким он был, поэтому обычно не следует беспокоиться о том, что анимация Flutter может «непосредственно» влиять на поток Native UI, вызывая замедление.Итак, какие преимущества даёт объединение потоков? Самое очевидное преимущество заключается в том, что на iOS теперь поддерживаются PlatformView с рендерингом без необходимости объединения потока буферизации. Другой случай — это ввод текста, поскольку до этого все взаимодействие происходило через Platform Channel. Асинхронное поведение вызвало множество проблем, таких как:
На iOS IME генерирует быстрый поток событий, а затем читает текст перед тем, как события будут обработаны в UI-потоке и отправлены обратно в платформенный поток. Часто логически требуется синхронный ответ, но из-за ограничений Platform Channel приходится использовать дополнительные затраты для достижения этой цели (постоянное извлечение CFRunLoop).
Основной идеей Platform Channel является асинхронность. Когда платформа требует что-то от ввода текста (координат выбора, текущего текста), ей нужен интерфейс, который может немедленно предоставить ответ. Однако через Platform Channel можно лишь активно отправлять все состояние клиенту, чтобы иметь возможность его использовать по мере необходимости.
Если же объединить всё в один поток, то FFI сможет выполнять синхронное взаимодействие с платформой, позволяя просто вызывать Dart-код и немедленно получать ответ. Это также позволит лучше сохранять некоторые различия между платформами при вводе текста, вместо того чтобы вынуждать унифицированный API ввода текста через Channel.> Также это поможет уменьшить множественное кэширование текста и состояния в памяти.
Кроме того, это упрощает прямое синхронное выполнение метода shouldOverrideUrlLoading
в WebView Android.
Однако такие изменения могут привести к некоторым негативным последствиям, таким как возможное возникновение ANR (Application Not Responding) для некоторых действий из-за недостаточной адаптации плагинов. Поэтому, если вы хотите отложить эту логику, вы можете добавить следующую конфигурацию:
<meta-data
android:name="io.flutter.embedding.android.DisableMergedPlatformUIThread"
android:value="true" />
Эта конфигурация выполняет --no-enable-merged-platform-ui-thread
, что меняет метку settings.merged_platform_ui_thread
на значение false
.
Конечно, цель всей команды Flutter заключается в полном удалении платформенных/message каналов, поэтому будущее полностью асинхронных каналов будет обязательно "уничтожено". Объединение потока для Flutter является неизбежным трендом, аналогично React Native, где синхронные вызовы и взаимодействие являются общими трендами для кросс-платформенного программирования.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )