Flutter 3.10 adapted singleton Window is deprecated, let’s understand View.of and PlatformDispatcher together

After the release of Flutter 3.10, you may have noticed that a sentence was mentioned in its release note : Window singleton related will be deprecated, and this change is to support the related implementation of multi-window in the future .

So this is a related improvement to support multi-windows. Multi-windows are more common in PC scenarios, but they need to be compatible with Mobile scenarios, so this change is made in advance.

As shown in the figure below, if it is specific to the corresponding API scenario, it mainly WidgetsBinding.instance.windowinvolves MediaQueryData.fromWindowthe adaptation of interfaces such as and , because WidgetsBinding.instance.windowis about to be deprecated.

You can still run without being suitable, but the technical debt of the upgrade will accumulate later.

First of all, there may be a question, why is there a usage scenario that needs to be WidgetsBinding.instance.windowused ? In simple terms, it can be summarized as follows:

  • no BuildContext, don't want to importBuildContext
  • What you don't want to get MediaQueryDatais affected where BuildContext, for example, padding changes when the keyboard pops up and is affected by parameters Scaffoldunder etc.

This part can be seen in detail: "MediaQuery and build optimization secrets you don't know" .

Then starting from 3.10, for WidgetsBinding.instance.windowcan be compatible through the new API method:

  • If it exists BuildContex, it can be View.ofobtained FlutterView, which is the most recommended official alternative
  • If there is BuildContexno objectPlatformDispatcher to getviews

I have noticed here. What is used now is that View.ofthe FlutterViewobject is called View instead of "Window". The corresponding MediaQueryData.fromWindowAPI is also deprecated and changed to MediaQueryData.fromView. The basis for this modification is:

At first, Flutter assumed that it only supports one Window scenario, so there will be SingletonFlutterWindowsuch instance window object. At the same time window, the attribute provides many functions that have nothing to do with the window itself, which will appear very different under the multi-window logic.

Then let us use the "long story" to briefly introduce the special features of these two scenes.

There is a BuildContext

Returning to this adjustment, the first is the scene where there is a BuildContext, as shown in the following code, for the scene where there BuildContexis , View.ofthe relevant adjustments are:

/// 3.10 之前
double dpr = WidgetsBinding.instance.window.devicePixelRatio;
Locale locale = WidgetsBinding.instance.window.locale;
double width =
    MediaQueryData.fromWindow(WidgetsBinding.instance.window).size.width;


/// 3.10 之后
double dpr = View.of(context).devicePixelRatio;
Locale locale = View.of(context).platformDispatcher.locale;
double width =
    MediaQueryData.fromView(View.of(context)).size.width;

It can be seen that there must be an Viewinternal InheritedWidget, which FlutterViewwill BuildContextbe shared through to provide parameter capabilities similar to "window", and the parameters View.ofobtained :

  • When the value of the property FlutterViewitself changes, contextthe update of the binding will not be notified. This behavior is similar to the previous WidgetsBinding.instance.window
  • Only when FlutterViewthe itself changes, such as contextdrawing to a FlutterViewdifferent , will contextthe update of the corresponding binding be triggered

It can be seen that View.ofthis behavior considers FlutterViewthe update scenario under "many". If it needs to be bound to the change update of specific corresponding parameters, such as sizeetc. , it still needs to be implemented through the previous MediaQuery.of/ MediaQuery.maybeOf.

ViewFor , each must be independent and unique . In a Widget Tree, a can only associated with one , which is mainly reflected in the implementation of the ID.FlutterViewFlutterViewViewFlutterViewGlobalObjectKey

A brief summary: In the BuildContexexisting scene, you can simply WidgetsBinding.instance.windowreplace with View.of(context), and don't worry about refactoring contextcaused by binding , because View.ofonly takes effect for the scene FlutterViewswitched by .

No BuildContext exists

For scenarios that do not exist or are inconvenient BuildContextto , the official provides PlatformDispatcher.viewsAPI to support, but because get viewscorresponds Mapto values, it is a Iterableobject , so how do we use PlatformDispatcher.viewsto adapt to the sceneBuildContextWidgetsBinding.instance.window without for 3.10 ?

PlatformDispatcherThe internal viewsmaintains a list of all FlutterViewavailable , providing BuildContextsupport for accessing views without a .

Under what circumstances would you say there will be BuildContext? For example, in Flutter , as shown in the figure below, 3.10 will use to insert a default runAppat the runApptime .platformDispatcher.implicitViewFlutterView

implicitViewWhat is it? In fact, implicitViewis the object PlatformDispatcher._viewswhose id is 0 FlutterView, and is viewsalso the objectIterable in this by default.first

That is to say, in the scenario where there BuildContextis , platformDispatcher.views.firstthe corresponding instance.windowimplementation of .

/// 3.10 之前
MediaQueryData.fromWindow(WidgetsBinding.instance.window)
/// 3.10 之后
MediaQueryData.fromView(WidgetsBinding.instance.platformDispatcher.views.first)

Why not use implicitViewthe object ? Because it is implicitViewcurrently a transitional solution, the official hopes that the concept of implicit view should not always exist in multi-view scenarios, but that the application itself should actively request to create a window to provide a view for drawing.

So for the implicitViewcurrently officially provided _implicitViewEnabledfunction, you can control whether the engine supports it through configurable bits implicitView, that is, it may be null at any time implicitViewin subsequent updates, which is why we should not use it externally , and it is configured at runApptime , so it never changes after the app is up and running, and if it's empty at startup, it will always be null.

PlatformDispatcher.instance.views[0]In the previous single-view scene, no matter whether there is a window, the similar implicitViewwill always exist; in the multi-window scene, PlatformDispatcher.instance.viewsit will follow the window change.

In addition, we access WidgetsBinding.instance.platformDispatcher.viewsthrough viewsinstead of directly PlatformDispatcher.instance.views, because usually the official recommends accessing under Binding dependencies PlatformDispatcher.

Except runApp()for ensureInitialized()scenarios where PlatformDispatcher needs to be accessed before or .

In addition, as shown in the figure below, through the implementation of the window part of the code in the Engine, we can see that the default id we need FlutterViewis the relevant basis for id 0, so this is also the logic of our compatibility support WidgetsBinding.instance.platformDispatcher.viewsthrough .

at last

Finally, to sum up, having said so much, it is nothing more than WidgetsBinding.instance.windowreplacing View.of(context), if there are still some showy operation scenarios, you can use it WidgetsBinding.instance.platformDispatcher.views, and if you are not afraid of subsequent pitfalls, you can even use it directly WidgetsBinding.instance.platformDispatcher.implicitView.

There are so many explanations on the whole, mainly to give everyone a background understanding of this change, and at the same time have a further understanding of the progress of multi-window implementation in the future . I believe that the next version of multi-window should be able to meet you.

For more discussion see:

  • https://github.com/flutter/flutter/issues/120306
  • https://github.com/flutter/engine/pull/39553
  • https://github.com/flutter/flutter/issues/116929
  • https://github.com/flutter/flutter/issues/99500
  • https://github.com/flutter/engine/pull/39788

Guess you like

Origin blog.csdn.net/ZuoYueLiang/article/details/130724747