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.window
involves MediaQueryData.fromWindow
the adaptation of interfaces such as and , because WidgetsBinding.instance.window
is 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.window
used ? In simple terms, it can be summarized as follows:
- no
BuildContext
, don't want to importBuildContext
- What you don't want to get
MediaQueryData
is affected whereBuildContext
, for example, padding changes when the keyboard pops up and is affected by parametersScaffold
under 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.window
can be compatible through the new API method:
- If it exists
BuildContex
, it can beView.of
obtainedFlutterView
, which is the most recommended official alternative - If there is
BuildContex
no objectPlatformDispatcher
to getviews
I have noticed here. What is used now is that View.of
the FlutterView
object is called View instead of "Window". The corresponding MediaQueryData.fromWindow
API 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
SingletonFlutterWindow
such instance window object. At the same timewindow
, 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 BuildContex
is , View.of
the 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 View
internal InheritedWidget
, which FlutterView
will BuildContext
be shared through to provide parameter capabilities similar to "window", and the parameters View.of
obtained :
- When the value of the property
FlutterView
itself changes,context
the update of the binding will not be notified. This behavior is similar to the previousWidgetsBinding.instance.window
- Only when
FlutterView
the itself changes, such ascontext
drawing to aFlutterView
different , willcontext
the update of the corresponding binding be triggered
It can be seen that View.of
this behavior considers FlutterView
the update scenario under "many". If it needs to be bound to the change update of specific corresponding parameters, such as size
etc. , it still needs to be implemented through the previous MediaQuery.of
/ MediaQuery.maybeOf
.
View
For , 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.FlutterView
FlutterView
View
FlutterView
GlobalObjectKey
A brief summary: In the BuildContex
existing scene, you can simply WidgetsBinding.instance.window
replace with View.of(context)
, and don't worry about refactoring context
caused by binding , because View.of
only takes effect for the scene FlutterView
switched by .
No BuildContext exists
For scenarios that do not exist or are inconvenient BuildContext
to , the official provides PlatformDispatcher.views
API to support, but because get views
corresponds Map
to values
, it is a Iterable
object , so how do we use PlatformDispatcher.views
to adapt to the sceneBuildContext
WidgetsBinding.instance.window
without for 3.10 ?
PlatformDispatcher
The internalviews
maintains a list of allFlutterView
available , providingBuildContext
support 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 runApp
at the runApp
time .platformDispatcher.implicitView
FlutterView
implicitView
What is it? In fact, implicitView
is the object PlatformDispatcher._views
whose id is 0 FlutterView
, and is views
also the objectIterable
in this by default.first
That is to say, in the scenario where there BuildContext
is , platformDispatcher.views.first
the corresponding instance.window
implementation of .
/// 3.10 之前
MediaQueryData.fromWindow(WidgetsBinding.instance.window)
/// 3.10 之后
MediaQueryData.fromView(WidgetsBinding.instance.platformDispatcher.views.first)
Why not use implicitView
the object ? Because it is implicitView
currently 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 implicitView
currently officially provided _implicitViewEnabled
function, you can control whether the engine supports it through configurable bits implicitView
, that is, it may be null at any time implicitView
in subsequent updates, which is why we should not use it externally , and it is configured at runApp
time , 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 similarimplicitView
will always exist; in the multi-window scene,PlatformDispatcher.instance.views
it will follow the window change.
In addition, we access WidgetsBinding.instance.platformDispatcher.views
through views
instead of directly PlatformDispatcher.instance.views
, because usually the official recommends accessing under Binding dependencies PlatformDispatcher
.
Except
runApp()
forensureInitialized()
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 FlutterView
is the relevant basis for id 0, so this is also the logic of our compatibility support WidgetsBinding.instance.platformDispatcher.views
through .
at last
Finally, to sum up, having said so much, it is nothing more than WidgetsBinding.instance.window
replacing 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