An overview of the
In the last article, we described how the Android system called Engine:Run, and finally called the main() function in the FlutterUI layer, and the FlutterUI framework started initialization. The Window object is initialized and associated with Engine. FlutterUImain() is initialized in the process of FlutterEngine:Run, and the related logic processed by FlutterUI layer is registered in the local method of window.dart class, and the communication process between FlutterEngine and FlutterUI is established. Decompose Flutterengine-related events into the processing logic of different Binding classes.
The core logic
1.FlutterEngin initializes and creates the UI.window.dart object
2.FlutterEngine: The run method calls the processing logic of the FlutterUI layer and uses different BaseBinding subclasses to decompose engine events
3. Register the different BaseBinding processing logic into the uI.window layer’s local methods and logic processing
4. How to implement the code of FlutterUI layer and summarize a simple UI for FlutterEngine to render on Android SurfaceView
We all know that a fit communicates with the widow layer and the fit framework layer. The widow is the hub for both the widow layer and the widow layer, so what’s the minimum executable unit for a fit?
After the flutter engine is initialized, the onBeginFrame method in Window is called to build a frame. When the frame is completed, uI.window.render (sceneBuilder.build()) is called. The second frame is passed to the Flutter Engine to change the process of building the Widget by changing the render object generated by the Widget. This is then passed to the Flutter Engine to enable code interface changes, page jumps, etc.
Remember that each of the following three methods is called in preparation for building a frame
ui.window.onBeginFrame = beginFrame;
ui.window.render(sceneBuilder.build());
ui.window.scheduleFrame();
Copy the code
The UI.Window class is the interface between the Flutter engine and the FlutterUI framework.
1. The binding operation UI.Window of FlutterUI layer and FlutterEngine layer is mainly completed
2. Decompose events into the system
GestureBinding
ServicesBinding
SchedulerBinding
PaintingBinding,
SemanticsBinding
RendererBinding
WidgetsBinding
Copy the code
Provide a render object to uI.window.render (sceneBuilder.build()); Call the rendering Engine in Engine
4. Initialize the platform Plugin interface
4. Initialize multiple languages and regions
How w are window events split into different bindings for processing?
1.FlutterEngine communicates with The Widow class and FlutterUI, including Widget drawing and lifecycle management
2. The Window class returns the relevant event callback and call method to different Bindings class for decoupling, and each part completes the relevant operation
3. The FlutterUI layer communicates with the system framework layer by submitting the relevant parts of runApp package Flutter to the system framework
4. By directly using the Window class to draw the Frame, we can understand the Flutter layer. The FlutterUI layer is actually an extension and refinement of the Window construction.
Sequence of Flutter invocation. PNG
Core steps:
The decoupling of the Widgets layer and window layer is continued by inheriting the Mixin class of BindingBase. Different Bindings classes inherit BindingBase.
/// A concrete binding for applications based on the Widgets framework.
///
/// This is the glue that binds the framework to the Flutter engine.
class WidgetsFlutterBinding extends BindingBase with GestureBinding.ServicesBinding.SchedulerBinding.PaintingBinding.SemanticsBinding.RendererBinding.WidgetsBinding {
static WidgetsBinding ensureInitialized() {
if (WidgetsBinding.instance == null)
WidgetsFlutterBinding();
returnWidgetsBinding.instance; }}Copy the code
WidgetsFlutterBinding implements BindingBase by calling initInstances in the constructor of BindingBase, RunApp calls the ensureInitialized method to initialize all Binding objects from back to front by calling initInstances, as well as BindingBase completion of the Window decomposition
The constructor calls initInstances by default. The constructor calls initServiceExtensions 3 by default. BindingBase, SchedulerBinding, GestureBinding, RendererBinding, SemanticsBinding also call their own constructors. Complete the interaction between FlutterUI layer and FlutterEngineCopy the code
A class provided in the flutterUI framework that implements BindingBase
The specific function of each class is a look at the corresponding class: the default constructor calls initInstances, initServiceExtensions
Object (dart.core) BindingBase (binding.dart) The parent of all binding classes, Dart), PaintingBinding (binding.dart), ServicesBinding (binding.dart), and SchedulerBinding (binding.dart) GestureBinding (binding.dart) RendererBinding (binding.dart) RenderingFlutterBinding (binding.dart) WidgetsBinding (binding. Dart) FlutterUI unified registration entry WidgetsFlutterBinding TestWidgetsFlutterBinding (binding. Dart) (binding.dart)Copy the code
PaintingBinding
Bind brush library, handle image cache, and use with ServicesBinding
mixin PaintingBinding on BindingBase, ServicesBinding {
@override
void initInstances() {
super.initInstances();
_instance = this;
_imageCache = createImageCache();
if(shaderWarmUp ! =null) { shaderWarmUp.execute(); }}Copy the code
ServicesBinding
Listen for platform messages and direct them to BinaryMessages. [ServicesBinding] also registers a public [LicenseEntryCollector] LICENSE bundle found in the LICENSE file stored in the asset root directory and implements the ext.flutter. Evict service extension
mixin ServicesBinding on BindingBase {
@override
void initInstances() {
super.initInstances();
_instance = this;
window
..onPlatformMessage = BinaryMessages.handlePlatformMessage;
initLicenses();
}
Copy the code
SchedulerBinding
A scheduler that runs the following:
- Transient callback, triggered by the system’s [window. onBeginFrame]
Callbacks used to synchronize the behavior of the application to the system display. For example, triggers for [Ticker] and [AnimationController] come from these.
-
Persistent Callbacks, triggered by the system’s [window.ondrawFrame] callback, are used to update the system’s display execution after transient callbacks, for example, the rendering layer uses it to drive its rendering pipeline.
-
- Post-frame callbacksRun only after a persistent callback
Before returning from the [window. onDrawFrame] callback. * Non-rendering tasks that run between frames. These priorities are given and executed in order of priority according to A
mixin SchedulerBinding on BindingBase, ServicesBinding {
@override
void initInstances() {
super.initInstances();
_instance = this;
window.onBeginFrame = _handleBeginFrame;
window.onDrawFrame = _handleDrawFrame;
SystemChannels.lifecycle.setMessageHandler(_handleLifecycleMessage);
readInitialLifecycleStateFromNativeWindow();
}
Copy the code
Listen for platform messages and direct them to BinaryMessages. [ServicesBinding] also registers a public [LicenseEntryCollector] LICENSE bundle found in the LICENSE file stored in the asset root directory and implements the ext.flutter. Evict service extension.
mixin ServicesBinding on BindingBase {
@override
void initInstances() {
super.initInstances();
_instance = this;
window
..onPlatformMessage = BinaryMessages.handlePlatformMessage;
initLicenses();
}
Copy the code
GestureBinding
When [PointerDownEvent] [GestureBinding] received (from [Window. OnPointerDataPacket], by. Interpret [PointerEventConverter]) and execute [hitTest] to determine which [HitTestTarget] node is affected. (Other binding tests are expected to be implemented to delay the [hitTest] testable object. For example, the render layer extends to RenderView and the rest of the render object hierarchy.
mixin GestureBinding on BindingBase implements HitTestable, HitTestDispatcher, HitTestTarget {
@override
void initInstances() {
super.initInstances();
_instance = this;
window.onPointerDataPacket = _handlePointerDataPacket;
}
Copy the code
RendererBinding
/// The glue between the render tree and the Flutter engine.
mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, SemanticsBinding, HitTestable {
@override
void initInstances() {
super.initInstances();
_instance = this;
_pipelineOwner = PipelineOwner(
onNeedVisualUpdate: ensureVisualUpdate,
onSemanticsOwnerCreated: _handleSemanticsOwnerCreated,
onSemanticsOwnerDisposed: _handleSemanticsOwnerDisposed,
);
window. onMetricsChanged = handleMetricsChanged .. onTextScaleFactorChanged = handleTextScaleFactorChanged .. onPlatformBrightnessChanged = handlePlatformBrightnessChanged .. onSemanticsEnabledChanged = _handleSemanticsEnabledChanged .. onSemanticsAction = _handleSemanticsAction; initRenderView(); _handleSemanticsEnabledChanged();assert(renderView ! =null);
addPersistentFrameCallback(_handlePersistentFrameCallback);
_mouseTracker = _createMouseTracker();
}
Copy the code
WidgetsBinding
/// The glue between the widgets layer and the Flutter engine.
mixin WidgetsBinding on BindingBase, SchedulerBinding, GestureBinding, RendererBinding, SemanticsBinding {
@override
void initInstances() {
super.initInstances();
_instance = this;
buildOwner.onBuildScheduled = _handleBuildScheduled;
window.onLocaleChanged = handleLocaleChanged;
window.onAccessibilityFeaturesChanged = handleAccessibilityFeaturesChanged;
SystemChannels.navigation.setMethodCallHandler(_handleNavigationInvocation);
SystemChannels.system.setMessageHandler(_handleSystemMessage);
}
Copy the code
The source code to achieve
Fills the given widget and attaches it to the screen. The widget is constrained during layout, forcing it to fill the entire screen. If you want to Align widgets to one side of the screen (for example, the top), consider using the [Align] widget. If you want to center your widget, you can also use the [center] widget to call [runApp] again to detach the previous root widget from the screen and attach the given widget to its location. The newer widget tree is targeted at the previous widget tree, and any differences are applied to the underlying render tree, similar to what happens when [StatefulWidget] is called [state.setState] and rebuilt. If necessary, initialize the binding with [WidgetsFlutterBinding]. And I can see: [WidgetsBinding attachRootWidget], it is. Create the root widget widget hierarchy. [RenderObjectToWidgetAdapter attachToRenderTree], it creates a root element hierarchy of elements. [WidgetsBinding handleBeginFrame], it will be a widget pipeline pump to ensure that build a widget, elements and render tree.
voidrunApp(Widget app) { WidgetsFlutterBinding.ensureInitialized() .. attachRootWidget(app) .. scheduleWarmUpFrame(); }Copy the code
Bindingbase WidgetsBinding integration:
1. InitInstances is called by default in the constructor
2. InitServiceExtensions is called by default in the constructor
3. BindingBase, SchedulerBinding, GestureBinding, RendererBinding, SemanticsBinding are also called
4. Complete the interaction between FlutterUI layer and FlutterEngine
/// The glue between the widgets layer and the Flutter engine.
mixin WidgetsBinding on BindingBase, SchedulerBinding, GestureBinding, RendererBinding, SemanticsBinding {
@override
void initInstances() {
super.initInstances();
_instance = this;
buildOwner.onBuildScheduled = _handleBuildScheduled;
window.onLocaleChanged = handleLocaleChanged;
window.onAccessibilityFeaturesChanged = handleAccessibilityFeaturesChanged;
SystemChannels.navigation.setMethodCallHandler(_handleNavigationInvocation);
SystemChannels.system.setMessageHandler(_handleSystemMessage);
}
static WidgetsBinding get instance => _instance;
static WidgetsBinding _instance;
@override
void initServiceExtensions() {
super.initServiceExtensions();
registerBoolServiceExtension(
name: 'showPerformanceOverlay',
getter: () =>
Future<bool>.value(WidgetsApp.showPerformanceOverlayOverride),
setter: (bool value) {
if (WidgetsApp.showPerformanceOverlayOverride == value)
return Future<void>.value();
WidgetsApp.showPerformanceOverlayOverride = value;
return_forceRebuild(); }); WidgetInspectorService.instance.initServiceExtensions(registerServiceExtension);return true; } ()); }Copy the code
Glue between FlutterUI and FlutterEngineBindingBase
1. BindingBase initialization
The base class (also known as “Binding”) for mixins that provide singleton services. Use this class in the on clause of a mixin, inherit it, and implement [initInstances ()]. Mixins guarantee that the application’s life cycle can only be built once (or rather, if constructed twice, it will assert that it is in check mode). The top layer for writing applications will have a concrete class that inherits from [BindingBase] and uses all the various [BindingBase]mixins (for example, [ServicesBinding]). For example, the Widgets library introduces a binding called [WidgetsFlutterBinding] into the Flutter. The associated library defines how bindings are created. It can be implied (for example, [WidgetsFlutterBinding] automatically starts with [runApp], or the application may need to explicitly call the constructor. The glue between the widget layer and the Flutter engine. Called when the binding is initialized to register the service extension. Want to public service extension binding should override this method to use call to register their [registerSignalServiceExtension], [registerBoolServiceExtension], [registerNumericServiceExtension], and [registerServiceExtension] (by increasing complexity). This approach to the implementation of the implementation must call its superclass {@ macro flutter. The foundation. The bindingBase. RegisterServiceExtension} can also look at:
- Github.com/dart-lang/s…
2. Association with the Window class
The window that binds this binding. Many other bindings are defined as extensions to [BindingBase], for example, [ServicesBinding], [RendererBinding], and [WidgetsBinding]. Each of these binding defines and [UI Window] interactive behavior, for example, [ServicesBinding] register a [UI. Window. OnPlatformMessage] handler, And registered [RendererBinding] [UI. Window. OnMetricsChanged], [UI. Window. OnTextScaleFactorChanged], [UI. Window. OnSemanticsEnabledChanged], and [UI. Window. OnSemanticsAction] handler. Each of these other bindings can statically access [Window] separately, but this prevents the ability Windows that test these behaviors with impersonation from being used for validation purposes. Therefore, [BindingBase] exposes this [Window] for use by other bindings. [BindingBase] subclasses, such as [TestWidgetsFlutterBinding], you can override the accessor to return a different [Windows], for example [TestWindow].
abstract class BindingBase {
BindingBase() {
1.Initialize the instance itself2.Sign up for the extension service....... initInstances(); initServiceExtensions(); . } to obtainwindowClass UI. The Windowget window => ui.window;
voidInitInstances () {} Registers the extended service@protected
@mustCallSuper
void initServiceExtensions() {
assert(() {
const String platformOverrideExtensionName = 'platformOverride';
registerServiceExtension(
name: platformOverrideExtensionName,
callback: (Map<String.String> parameters) async {
if (parameters.containsKey('value')) {
switch (parameters['value']) {
case 'android':
debugDefaultTargetPlatformOverride = TargetPlatform.android;
break;
case 'iOS':
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
break;
case 'fuchsia':
debugDefaultTargetPlatformOverride = TargetPlatform.fuchsia;
break;
case 'default':
default:
debugDefaultTargetPlatformOverride = null;
}
_postExtensionStateChangedEvent(
platformOverrideExtensionName,
defaultTargetPlatform.toString().substring('$TargetPlatform. '.length),
);
await reassembleApplication();
}
return <String.dynamic> {'value': defaultTargetPlatform
.toString()
.substring('$TargetPlatform. '.length), }; });return true; } ()); }... }Copy the code
window
How does the Flutter user UI layer relate to Windows
In the previous section, the system has created multiple Binding classes for us, and the main purpose is to distinguish the callback and interaction of FlutterEngine and FlutterUI respectively, so as to achieve the purpose of code decoupling
The most basic user interface of the host OS. There is an instance of Window on the system, you can do this by getting the FlutterUI property from [Window] how does the user access the Window interface? We’ll start with a minimalist example of a FlutterUI project calling an interface in FlutterEngine
How does Window draw the simplest frame on the screen
Rendering [Scene] on the GPU using the newly provided update application must be called within the scope of this function [onBeginFrame] or the [onDrawFrame] callback to be called. If this function is called a second time in a single [onBeginFrame] / [onDrawFrame] callback sequence or calls that are outside the scope of the callback are ignored. To record graphical operations, first create a [PictureRecorder] construct a [Canvas] and pass [PictureRecorder] to its constructor. Issued after all graphics operations, call [PictureRecorder endRecording] function on [PictureRecorder] get says it has released the final [Picture] graphics operations. Next, create a [SceneBuilder] and use Add [Picture][sceneBuilder.addPicture]. Use the [sceneBuilder.build] method and then get the [Scene] object from which you can display the object [render] functionality. Also see: [SchedulerBinding], which manages the scheduling of Flutter frame class frames. RendererBinding, the Flutter framework class, used to manage layouts and drawings.
flutterwindow.png
Core implementation:
color = const ui.Color(0xFF00FF00); Provide Frame data to Window UI.window.onBeginFrame = beginFrame; Process click event UI. Window. OnPointerDataPacket = handlePointerDataPacket; Calling the scheduleFrame method calls the native method to access Flutterengine uI.window.scheduleFrame ();Copy the code
SceneBuilder SceneBuilder = ui.sceneBuilder () // TODO(abarth): We should be able to add a picture without pushing a // container layer first. .. pushClipRect(physicalBounds) .. addPicture(ui.Offset.zero, picture) .. pop();
ui.window.render(sceneBuilder.build());
Copy the code
import 'dart:ui' as ui;
void beginFrame(Duration timeStamp) {
final double devicePixelRatio = ui.window.devicePixelRatio;
final ui.Size logicalSize = ui.window.physicalSize / devicePixelRatio;
finalui.ParagraphBuilder paragraphBuilder = ui.ParagraphBuilder( ui.ParagraphStyle(textDirection: ui.TextDirection.ltr), ) .. addText('Hello, world.');
finalui.Paragraph paragraph = paragraphBuilder.build() .. layout(ui.ParagraphConstraints(width: logicalSize.width));final ui.Rect physicalBounds = ui.Offset.zero & (logicalSize * devicePixelRatio);
final ui.PictureRecorder recorder = ui.PictureRecorder();
final ui.Canvas canvas = ui.Canvas(recorder, physicalBounds);
canvas.scale(devicePixelRatio, devicePixelRatio);
canvas.drawParagraph(paragraph, ui.Offset(
(logicalSize.width - paragraph.maxIntrinsicWidth) / 2.0,
(logicalSize.height - paragraph.height) / 2.0));final ui.Picture picture = recorder.endRecording();
finalui.SceneBuilder sceneBuilder = ui.SceneBuilder() .. pushClipRect(physicalBounds) .. addPicture(ui.Offset.zero, picture) .. pop(); ui.window.render(sceneBuilder.build());
}
void main() {
ui.window.onBeginFrame = beginFrame;
ui.window.scheduleFrame();
}
Copy the code
conclusion
From the above analysis, window-related interfaces have continued to be decoupled to different binding objects, and all initialization operations are performed in the initInstances() method
1. Call runApp to start an entry to the AppWidget layer
2. Call the ensureInitialized method of WidgetsFlutterBinding to initialize all subclasses of BindingBase
3. Mixin classes are initialized from back to front in the inheritance order
Based on the above analysis and demo, we can easily understand the separation of Widow events, initialization of different BindingBases, and Window render object callback to The Flutterengin layer to provide render objects. The following articles will introduce The core function of FlutterUI is to merge the user interface into a frame, including 1. Window management 2. Platform message management 3. User interface management 4. The processing logic of touch and click events is more detailed. The framework analysis will be done in the following files. First, the core logic will be made, and the framework knowledge of Flutter details will be learned. In the framework of code is according to the different instances associated code in the SDK, youtube has a lot of tutorials, avoid the meticulous details up and spend too much time, the navigation first set, while driving on the road, bad direction is wrong, improve the efficiency of execution, the event can be turned to solve the — — — — — — — personal methodology of study and work, Hope we can discuss together