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个重要绑定:SchedulerBindingRendererBindingWidgetsBinding
  • 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

 

posted on 2020-10-24 16:53  我是你爷爷的爷爷  阅读(524)  评论(0编辑  收藏  举报

导航