Flutter框架分析(笔记)
一、总览和window
1. 渲染流水线 Render pipeline
Vsync
| ScheduleFrame
Animate ------------------->
| <-------------------
Layout Flutter 框架 OnBeginFrame Engine
| <--------------------
Paint onDrawFrame
| --------------------->
scene Scene
2.window Flutter中的window是单例
和javascript 开发一样,Flutter 底层的页面最后也是展示到window上的。主要对上层提供屏幕尺寸,调度接口,图形绘制接口,输入事件回调等核心服务
总体来说,window集中提供了Flutter引擎中和图形界面相关的接口
二、Flutter 框架的初始化
void runApp(Widget app) {
WidgetsFlutterBinding.ensureInitialized()
..attachRootWidget(app)
..scheduleWarmUpFrame();
}
1.runApp入口做了三件事
a:WidgetsFlutterBinding.ensureInitialized() 通过mixin 混入了一些绑定,重要的有以下三个:
每个Binding都是继承自BaseBinding,BaseBinding的构造里面initInstances,还有返回了一个window对象。
举例:可以看到在调用initInstances,内部做的事情其实就是把一些Window对上提供的接口绑定到window对象上。如下面这个就是把处理点击的手势绑定到window并返回一个回调。
mixin GestureBinding on BindingBase implements HitTestable, HitTestDispatcher, HitTestTarget {
@override
void initInstances() {
super.initInstances();
_instance = this;
window.onPointerDataPacket = _handlePointerDataPacket;
}
1⃣️ ScheduleBinding 绑定onBeginFrame和onDrawFrame的回调
mixin SchedulerBinding on BindingBase, ServicesBinding {
@override
void initInstances() {
super.initInstances();
_instance = this;
window.onBeginFrame = _handleBeginFrame;
window.onDrawFrame = _handleDrawFrame;
SystemChannels.lifecycle.setMessageHandler(_handleLifecycleMessage);
}
2⃣️ RenderBinding PipelineOwner 和RenderView 做渲染的绑定
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();
}
3⃣️ WidgetsBinding BuildOwner 主要做build构建
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);
}
b:attachRootWidget(app) 通过attach把在ensureInitialized()绑定的Renderview和Element给关联了起来
void attachRootWidget(Widget rootWidget) {
_renderViewElement = RenderObjectToWidgetAdapter<RenderBox>(
container: renderView,
debugShortDescription: '[root]',
child: rootWidget
).attachToRenderTree(buildOwner, renderViewElement);
}
c:scheduleWarmUpFrame 给engine申请一帧,把build构建和Layout paint后的scene送给Engine显示到屏幕
void scheduleWarmUpFrame() {
...
Timer.run(() {
...
handleBeginFrame(null);
...
});
Timer.run(() {
...
handleDrawFrame();
...
});
}
- 3个重要绑定:
SchedulerBinding,RendererBinding和WidgetsBinding。 - 2个“owner”:
PipelineOwner(渲染流水线)和BuildOwner(管理widget的重建)。 - 2颗树的根节点:render tree根节点
RenderView;element tree根节点RenderObjectToWidgetElement。
三、Widget Element RenderObject
1.Widget 是Element的描述和配置,StatefulWidget statelessWidget 里面的build()方法实际调用的其实是Element
2.Element ,只关心自己的Element tree , Element 的主要工作都处于渲染流水线都build阶段。
3.RenderObject,负责渲染流程,layout和paint阶段。
widget:
@immutable
abstract class Widget extends DiagnosticableTree {
const Widget({ this.key });
...
@protected
Element createElement();
...
}
StatelessWidget:
abstract class StatelessWidget extends Widget {
/// Initializes [key] for subclasses.
const StatelessWidget({ Key key }) : super(key: key);
@override
StatelessElement createElement() => StatelessElement(this);
@protected
Widget build(BuildContext context);
}
StatefullWidget:
abstract class StatefulWidget extends Widget {
@override
StatefulElement createElement() => StatefulElement(this);
@protected
State createState();
}
State:
abstract class State<T extends StatefulWidget> extends Diagnosticable {
T get widget => _widget;
T _widget;
BuildContext get context => _element;
StatefulElement _element;
bool get mounted => _element != null;
void initState() { }
void didUpdateWidget(covariant T oldWidget) { }
void setState(VoidCallback fn) {
final dynamic result = fn() as dynamic;
_element.markNeedsBuild();
}
void deactivate() { }
void dispose() { }
Widget build(BuildContext context);
void didChangeDependencies() { }
}
通过State代码可以看到,context =>返回的是_element ,build的方法传入的BuildContext 是_element,也就是Statefullwidget的CreateElement()方法获取到的element
1.State 拥有widget和element
2.context 就是element
3.build()方法传入的就是element
4.mounted ,判断的是element是否为null,也就是State是否有关联到element tree的element
5.setState,只是简单的判断element是不是需要重新Build。如果element为null,setState调用会报错,所以需要用mounted判断一下
6.didChangeDependencies,当依赖的数据发生变化的时候的回调,主要就是inheritedWidget的数据依赖
7.didUpdateWidget,当State里面的widget被更换了的回调。如果类型相同,是可以更换widget的
8.build(),构建。。。。
Element:
abstract class Element extends DiagnosticableTree implements BuildContext {
Element _parent;
Widget _widget;
BuildOwner _owner;
dynamic _slot;
void visitChildren(ElementVisitor visitor) { }
Element updateChild(Element child, Widget newWidget, dynamic newSlot) {
}
void mount(Element parent, dynamic newSlot) {
}
void unmount() {
}
void update(covariant Widget newWidget) {
}
@protected
Element inflateWidget(Widget newWidget, dynamic newSlot) {
...
final Element newChild = newWidget.createElement();
newChild.mount(this, newSlot);
return newChild;
}
void markNeedsBuild() {
if (dirty)
return;
_dirty = true;
owner.scheduleBuildFor(this);
}
void rebuild() {
if (!_active || !_dirty)
return;
performRebuild();
}
@protected
void performRebuild();
}
1.markNeedsBuild,标记element为dirty,需要重build,在渲染下一帧的时候这个element会被重绘。
2.updateChild(),
a:新widget为空,老widget为空,则啥也不做
b:新widget为空,老widget不为空,则widget被移除
c:新widget不为空,老widget为空,则创建一个element
d:新widget不为空,老widget不为空,则调用update,具体由子类实现
3.新element被实例化后,调用mount加入element tree,移除的时候调用unmount移除
4.rebuild 在渲染流水线build阶段被调用,具体的重绘,在performRebuild,由子类实现
abstract class ComponentElement extends Element {
ComponentElement(Widget widget) : super(widget);
Element _child;
@override
void performRebuild() {
Widget built;
built = build();
_child = updateChild(_child, built, slot);
}
Widget build();
}
performRebuild会调用build方法,实例化一个widget,由子类实现
重点:
statelessElement:
class StatelessElement extends ComponentElement {
@override
Widget build() => widget.build(this);
@override
void update(StatelessWidget newWidget) {
super.update(newWidget);
_dirty = true;
rebuild();
}
}
1.widget的build方法,实际是由他创建的element的build方法中调用,在performRebuild的时候被执行重绘。而且可以看到widget.build(this),可以知道buildContext传入的context上下文就是这个widget对应的element
statefullelement
class StatefulElement extends ComponentElement {
/// Creates an element that uses the given widget as its configuration.
StatefulElement(StatefulWidget widget)
: _state = widget.createState(),
super(widget) {
_state._element = this;
_state._widget = widget;
}
@override
Widget build() => state.build(this);
@override
void _firstBuild() {
final dynamic debugCheckForReturnedFuture = _state.initState()
_state.didChangeDependencies();
super._firstBuild();
}
@override
void deactivate() {
_state.deactivate();
super.deactivate();
}
@override
void unmount() {
super.unmount();
_state.dispose();
_state._element = null;
_state = null;
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
_state.didChangeDependencies();
}
}
1.firstBuild -- _state.initState() -- _state.didChangeDependencies()
2.deactivate() -- _state.deactivate()
3.unmount -- _state.dispose() -- _state.element = null
4.didChangeDependencies -- didChangeDependencies()
RenderObject负责渲染流水线布局(layout)阶段和绘制(paint)阶段的工作。同时也维护render tree
abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin implements HitTestTarget {
void markNeedsLayout() {
...
}
void markNeedsPaint() {
...
}
void layout(Constraints constraints, { bool parentUsesSize = false }) {
...
if (sizedByParent) {
performResize();
}
...
performLayout();
...
}
void performResize();
void performLayout();
void paint(PaintingContext context, Offset offset) { }
}
四、Flutter框架运行
1.State.setState(),到engine那去请求一帧。主要做到就是标记element为dirty,然后添加到dirtyElement的列表中
2.等待Vsync信号到来,然后渲染流水线开始重建新的一帧,最后送入engine显示。主要是onBeginFrame,onDrawFrame--drawFrame,显示buildOwner buildScope,构建,然后pipelineOwner,flushLayout和flushPaint,执行布局和绘制,最后window render 把scene,请求engine显示到屏幕。
重点:
setState后,执行顺序:也就是setState后,最后window会去engine请求一帧
1.Widget: setState() ->Element: element.markNeedBuild ->Element: owner.scheduleBuildFor dirty = true ... -> BuildOwner: scheduleBuildFor _dirtyElements.add(element) ->
Binding: handleBuildSchedule ensureVisualupdate -> ScheduleBinding: _scheduleFrame -> Window: scheduleFrame 向engine发起请求一帧
build阶段:dirtyElement排序,然后执行rebuild ,performRebuild,最后调用到State的build方法,然后由父到子节点开始rebuild
1.Element重建的时候其子Element也都会重建
2.流程:
_dirtyElements sort 排序 -> element.rebuild -> element.performRebuild -> State.build ===>Widget ===> updateChild -> 循环由父到子Element执行,实现rebuild
五、Flutter框架 ---Animate动画
1.怎么实现动画
a:State混入SingleTickerProviderStateMixin
b:initState初始化AnimationController和Animate=Tween()
c:build里面用到Animate.value或Animate的其他值
d:dispose释放Controller
2.SingleTicker Ticker给动画提供Vsync信号
3.Tween里面用到transform,把AnimationController只能定义0-1的值给转换了
4.simulation,动画的本质,外力作用下不同时间点的运动状态的变化
5.evaluatable.evaluate计算transform的转换
6.Tween,线性插值,还有其他的插值,curveAnimation,非线性插值
7.定义自己的非线性动画,只需重写变换函数
class shakeCurve extends Curve{
@override
double transform(double t){
return sin(t*pi*);
}
}
流程:1 singleTicker 2 Ticker驱动Vsync 3Ticker源码执行ScheduleTick 4ScheduleBinding,加入到Transient 5window onbeginFrame 和onDrawFrame 6以上ticker的有AnimationController.createTicker驱动
8 动画的值,Animation的transform做计算转换
六Flutter框架 Layout 布局
1.一下一上
由下到上传递尺寸size
有上到下传递约束
先layout父,避免重复layout子。===》pipelineOwner.flushLayout,实际是renderBox做的,它是renderVIew的子类
2.Alignment,孩子在父的位置有Alignment决定的
左到右 -1===1
上到下 -1===1
七Flutter框架 Paint 绘制
绘制过程其实就是把Element Tree 转换成Layer Tree 图层树的过程,然后把scene场景送入Engine显示。绘制过程比较复杂
贴上大神的博客地址:https://juejin.im/post/6844903791427321863#comment
浙公网安备 33010602011771号