After the Google conference, a lot of people asked me about my Flutter, many of which were related to interviews, and now some job applicants have started to list their Flutter requirements. Finally, I thought I would write a summary, which is also a phase review of my Flutter.
A complete study of the system is required at ⚠️, but there are only a few tips here, please check the Dart/Flutter website for more information.Copy the code
This article is a summary of knowledge points, if in doubt can click on the link to learn more details, or refer to my nuggets column.
The Dart part
Dart is a combination of dynamic and static languages, but it provides a few different, or interesting, concepts.
-
1. Dart is a strongly typed language, but you can use var to declare variables, and Dart will derive its own data types. Var is actually syntax sugar at compile time. Dynamic indicates a dynamic type. When compiled, it is actually an object type. There is no type checking at compile time, but at run time.
-
2. Dart statements such as if support only bool, and Switch statements support String.
-
3. Arrays and lists are the same in Dart.
-
4. In Dart, Runes stand for symbolic text, which is a UTF-32 encoded string. For example, Runes input = new Runes(‘\u{1f596} \u{1f44d}’);
-
Dart supports closures.
-
6. Dart has two types of number: int and double.
-
7. Dart concatenates operators to facilitate the configuration of logic.
event .. id = 1 .. type = "" .. actor = "";Copy the code
- 8. The assignment operator
Some interesting assignment operators are:
AA ?? If AA is null, return 999 AA?? = "999" /// If AA is empty, set AA to 999 AA ~/999 ///AA is divisible into 999Copy the code
- 9. Optional method parameters
The Dart method can set parameter defaults and specify names.
For example, getDetail(Sting userName, reposName, {branch = “master”}){}. If branch is not set, the default is “master”. Parameter types can be specified or not specified. GetRepositoryDetailDao (” aaa”, “BBBB “, branch: “dev”); .
- 10. Scope
Dart
No keywordspublic
、private
Etc modifier,_
The bottom horizontal directly representsprivate
, but there are@protected
Annotation.
- 11, construction method
Multiple constructors in Dart can be implemented using named methods.
The default constructor can only have one, but you can create a class with empty arguments using the model.empty () method. The method name is whatever you like, and you can only specify this. Name in the constructor:
class ModelA { String name; String tag; // The default constructor, assigned to name and tag ModelA(this.name, this.tag); // Return an empty ModelA modela.empty (); // Return a ModelA modela.forname (this.name) with name set; }Copy the code
- Getter setter override
All base types, classes, and so on in Dart inherit Object, default to NULL, have a getter and setter, and if it’s final or const, it only has a getter method. Both objects support getter and setter overrides:
@override
Size get preferredSize {
return Size.fromHeight(kTabHeight + indicatorWeight);
}
Copy the code
- 13. Assert
Assert (unicorn == null) is valid only for checking patterns. During development, assert(unicorn == null); If the condition is true, it is normal to throw an exception. Otherwise, an exception should be thrown. This is usually used to determine what state should not occur somewhere in the development process.
- 14. Override the operator as shown below
operator
After the +/- operation on the class.
class Vector { final int x, y; Vector(this.x, this.y); Vector operator +(Vector v) => Vector(x + v.x, y + v.y); Vector operator -(Vector v) => Vector(x - v.x, y - v.y); Void main() {final v = Vector(2, 3); final w = Vector(2, 2); assert(v + w == Vector(4, 5)); assert(v - w == Vector(0, 1)); }Copy the code
Overloaded operators are supported:
- Classes, interfaces, inheritance
Dart has no interfaces. Any class can be an interface. To implement a class as an interface, just use implements and copy the superclass method.
Dart supports mixins, which should be extends, mixins, and implements in the order they appear.
-
Zone
Dart uses zones to specify the environment in which the code is executed. Like a sandbox concept, in the Flutter C++ runs Dart and runs the runZoned method within _runMainZoned. Catch information such as global exceptions within the runtime environment:
runZoned(() {
runApp(FlutterReduxApp());
}, onError: (Object obj, StackTrace stack) {
print(obj);
print(stack);
});
Copy the code
You can also register methods for runZoned and perform callbacks as needed, as shown in the following code, so that anywhere within a Zone that can retrieve the onData ZoneUnaryCallback can call handleData
/ / / eventually need to deal with the handleData (result) {print (" VVVVVVVVVVVVVVVVVVVVVVVVVVV "); print(result); } / / / return get a ZoneUnaryCallback var onData = Zone. The current. The registerUnaryCallback < dynamic, int > (the handleData); /// Run ZoneUnaryCallback to return the data zone.current.rununary (onData, 2);Copy the code
Async logic can be inserted with scheduleMicrotask:
Zone.current.scheduleMicrotask((){
//todo something
});
Copy the code
See also: A Detailed explanation of the Complete Development of Flutter (xi, Comprehensive and In-depth Understanding Stream)
-
Future
A Future simply encapsulates the use of a Zone.
For example, future. microTask mainly executes the scheduleMicrotask of the Zone, while result._complete calls _zone.runUnary and so on.
factory Future.microtask(FutureOr<T> computation()) { _Future<T> result = new _Future<T>(); scheduleMicrotask(() { try { result._complete(computation()); } catch (e, s) { _completeWithErrorCallback(result, e, s); }}); return result; }Copy the code
Dart
Can be throughasync
/await
orFuture
Define asynchronous operations, but in factasync
/await
It’s just syntax sugar, which is converted by the compilerFuture
.
Interested to see here:
generators
code_generator.dart
Overview of the complete development of the Stream
-
Stream
A Stream is another encapsulation of a Zone.
Another async operation in Dart, async* / yield or Stream, defines Stream async. Async * / yield is just syntax sugar and is converted to Stream by the compiler. Stream also supports synchronous operations.
StreamController, StreamSink, StreamSubscription, StreamSink, StreamSubscription
-
StreamController: As described in the class name, controls the entire Stream process and provides interfaces for creating various streams of events.
-
StreamSink: Generally serves as an entry point for events, such as Add, addStream, etc.
-
Stream: The event source itself, which can be used to listen to or transform events, such as LISTEN and WHERE.
-
StreamSubscription: An object that has been subscribed to an event, ostensibly to manage subscribed operations such as cacenl and pause, but also internally as a key to relay events.
2) Stream is created by StreamController. Adding events via StreamSink; Listen for events via Stream; StreamSubscription is used to manage subscriptions.
3) Stream supports various variations, such as map, expand, WHERE, take, and conversion to Future.
See also: A Detailed explanation of the Complete Development of Flutter (xi, Comprehensive and In-depth Understanding Stream)
Flutter part
The main difference between The Flutter UI and React Native is that the Flutter UI is rendered directly via Skia, whereas React Native converts js controls into Native controls and renders them Native. See more about this: An in-depth look at mobile cross-platform development.
-
There are four trees in Flutter: Widget, Element, RenderObject and Layer. The relationship between Widget and Element is one-to-many.
-
The Element holds the Widget and the RenderObject, and the Element has a one-to-one relationship with the RenderObject (except that the Element does not have a RenderObject, Such as ComponentElement does not have RenderObject),
-
When the isRepaintBoundary of a RenderObject is true, then each area forms a Layer, so not every RenderObject has a Layer, because this is affected by isRepaintBoundary.
More information can be found in the Complete Development of Flutter: A Practical Explanation (IX. In-depth Drawing Principles).
-
Widgets in the Flutter are immutable and remain one frame at a time. If any changes occur, the State is saved across frames through the State, while RenderObject is the real layout and array drawing. Element acts as a bridge between the two. State is stored in the Element.
-
The Flutter
BuildContext
It’s just an interface, andElement
I implemented it. -
SetState in the Flutter calls markNeedsBuild, which internally marks the Element as Dirty, and then WidgetsBinding. DrawFrame will be drawn on the next frame. This shows that setState does not take effect immediately.
-
RenderObject in Flutter passes markNeedsPaint() after attch/ Layout; To redraw the page, the process is roughly as follows:
The update area is defined upwards via the isRepaintBoundary, and the update is triggered downwards by the requestVisualUpdate method.
- normal
RenderObject
The order of the layout-related method calls is:layout
->performResize
->performLayout
->markNeedsPaint
,But users generally don’t call it directlylayout
, butthroughmarkNeedsLayout
, the specific process is as follows:
-
Json data in Flutter is converted from String to Object through a Map type.
-
Inheritedwidgets are generally used to share states, such as Theme, Localizations, MediaQuery, etc., so that we can get the shared state through context. For example, ThemeData theme = theme.of (context);
In Element inheritFromWidgetOfExactType method, there is a Map < Type, InheritedElement > _inheritedWidgets object.
The _inheritedWidgets function is null and initialized only if the parent is an InheritedWidget or is itself an InheritedWidget, which is what happens when the parent is an InheritedWidget. The Map is passed down and merged one level at a time.
So when we call inheritFromWidgetOfExactType through the context, you can find up to the parent Widget.
- By default, updates are judged mainly by runtimeType and key:
static bool canUpdate(Widget oldWidget, Widget newWidget) { return oldWidget.runtimeType == newWidget.runtimeType && oldWidget.key == newWidget.key; }}Copy the code
Life cycle in Flutter
initState()
Said that the currentState
Will and aBuildContext
But at this pointBuildContext
Not fully loaded, if you need to get it in this methodBuildContext
, you cannew Future.delayed(const Duration(seconds: 0, (){//context});
Once in a while.
More specifically, the SchedulerBinding is now used
-
DidChangeDependencies () is called after initState(), which is called when the dependencies of the State object change, as well as during initialization.
-
Deactivate () This method is called when the State is temporarily removed from the view tree and also when the page is switched. (Disappeared in the new version)
-
The Dispose () Widget is destroyed, and deactivate() is always called before this method is called.
-
DidUpdateWidge is called when the widget state changes.
-
StreamBuilder and FutureBuilder allow us to quickly build our asynchronous controls using Stream and Future.
-
The runApp startup entry in Flutter is actually a WidgetsFlutterBinding, It’s basically a BindingBase subclass GestureBinding, ServicesBinding, SchedulerBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding, etc. are created by combining mixins.
-
Dart threads in the Flutter exist in the form of event loops and message queues, including two task queues, one is an internal microTask queue and the other is an external Event queue, and microtask has a higher priority than Event.
Because microtasks have a higher priority than Events and block the Event queue, too many microtasks can cause a blocking block for external events such as touching, drawing, etc.
- Existing in the FlutterFour threads, respectively
UI Runner
,GPU Runner
,IO Runner
.Platform Runner
(Native main thread)“And can be passed in the Flutterisolate
orcompute
Perform true asynchronous operations across threads.
PlatformView
The native View can be nested into the Flutter UI via the PlatformView. This is actually achieved by using Presentation + VirtualDisplay + Surface, etc. The basic principle is as follows:
Using a technique similar to subscreen display, the VirtualDisplay class represents a VirtualDisplay and renders the contents of the VirtualDisplay on a Surface control by calling DisplayManager’s createVirtualDisplay() method. Dart will be notified of the Surface ID, and engine will find the corresponding Surface image memory data in memory and then draw it. em… Real-time control screenshot rendering display technology.
-
The Debug mode of the Flutter is JIT mode and the release mode is AOT mode.
-
Can be approved in a Flutter mixins AutomaticKeepAliveClientMixin, then rewrite wantKeepAlive hold page, remember to call in the page is hold the build super. Build. (because of the mixins feature).
-
The Flutter gesture event was judged mainly by competition:
The main hitTest is to combine all renderObjects corresponding to controls that need to be processed, from child to parent, into a list, and add them from the inside to the outside.
The for loop then executes the handleEvent method starting from the child in the queue header. The execution of the handleEvent is not interrupted by interception.
Generally, the Down event does not determine the winner. Most of the time, the winner will be determined when the MOVE or UP event.
When the arena is closed, there is only one winner, and no winner gets the first forced victory response in the queue.
There is also didExceedDeadline for additional processing of the Down event while holding Down, while gesture processing generally takes place in a subclass of GestureRecognizer.
More details can be found at the Detailed explanation of the Complete Development of Flutter (XiII).
-
The ListView slide in the Flutter is actually displayed by changing the layout of the Child in the ViewPort.
-
Common state management modes: Scope_Model, Flutter_redux, Fish_redux, Bloc + Stream and other modes. The details can be seen in the detailed explanation of the Complete Development of the Flutter.
Platform Channel
The Dart code can communicate with the native code via the Platform Channel.
BasicMessageChannel
: used to pass strings and semi-structured information.MethodChannel
: Used for method InvocationEventChanne
L: For communication of event Streams.
Also, the Platform Channel is not thread safe. More details can be found in The Understanding of the Flutter Platform Channel by Fomo Technology.
The mapping of basic data types is as follows:
Android start page
Flutter in the Android enabled by default in FlutterActivityDelegate. When they read from the Java AndroidManifset. Meta – data within XML tags, The IO. Flutter. App. Android. SplashScreenUntilFirstFrame sign if it is true, will start the Splash screen effect (similar to IOS start page).
Startup native code will read android. The state Richard armitage TTR event. Get the specified Drawable windowBackground, displays the startup splash screen effect, and then through flutterView. AddFirstFrameListener, Remove the splash screen from the onFirstFrame.
Ok, all here for the time being, there are problems to modify or complement, and then add.
Resources to recommend
- Making: github.com/CarGuo
- Open source Flutter complete project:Github.com/CarGuo/GSYG…
- Open source Flutter multi-case study Project:Github.com/CarGuo/GSYF…
- Open source Fluttre Practical Ebook Project:Github.com/CarGuo/GSYF…
Recommended for complete open source projects:
- GSYGithubApp Flutter
- GSYGithubApp React Native
- GSYGithubAppWeex