Flutter 启动流程

说起启动那必须从main方法开始呀

void main() => runApp(MyApp());
void runApp(Widget app) {
  WidgetsFlutterBinding.ensureInitialized()
    ..scheduleAttachRootWidget(app)
    ..scheduleWarmUpFrame();
}

runApp的代码很简单,传递一个Widget参数,然后执行了三行代码,三行代码代表了Flutter App启动的主要三个流程:

  1. binding初始化(ensureInitialized)
  2. 绑定根节点(scheduleAttachRootWidget)
  3. 绘制热身帧(scheduleWarmUpFrame)

binding初始化(ensureInitialized)

class WidgetsFlutterBinding extends BindingBase with GestureBinding, SchedulerBinding, ServicesBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {

static WidgetsBinding ensureInitialized() {
    if (WidgetsBinding.instance == null)
      WidgetsFlutterBinding();
    return WidgetsBinding.instance;
  }
}

mixin我们前面已经介绍过了,不难发现 WidgetsFlutterBinding 单例过程其实也是对7个mixin的binding的初始化 。
WidgetsFlutterBinding继承了BindingBase,在调用自己的构造器之前会先先执行了父类BindingBase构造函数。

  BindingBase() {
    developer.Timeline.startSync('Framework initialization');

    assert(!_debugInitialized);
    initInstances();
    assert(_debugInitialized);

    assert(!_debugServiceExtensionsRegistered);
    initServiceExtensions();
    assert(_debugServiceExtensionsRegistered);

    developer.postEvent('Flutter.FrameworkInitialization', {});

    developer.Timeline.finishSync();
  }

WidgetsBinding 覆盖了前面的 binding 的 initInstances(),所以 WidgetsBinding 的 initInstances() 会首先被调用,而 WidgetsBinding 的 initInstances 函数中先通过 super 向上调用 initInstances ,根据mixin的特性 执行顺序: initInstances 的执行顺序依次是:BindingBase -> GestureBinding -> SchedulerBinding -> ServicesBinding -> PaintingBinding -> SemanticsBinding -> RendererBinding -> WidgetsBinding,从而依次完成各个 Binding 的初始化相关工作。

RendererBinding

mixin RendererBinding on BindingBase,   
{

@override
void initInstance() {
super.initInstance();
_pipelineOwner = PipelineOwner(
……………
);
……………
initRenderView(){
renderView = RenderView(
configuration:createViewConfiguration(),
window:window
);
……………
}
}

}
}

PipelineOwner是渲染管道,它在widget渲染的阶段有重要的作用,具体的会在后续的渲染绘制会着重分析.
RenderView 就是我们屏幕真实显示的那个View,Flutter是单页面的UI框架,renderView就是这个时间点被初始化出来的。它是Render tree 的根节点,同时将当前设备的物理屏幕信息配置上。

SemanticsBinding

渲染辅助类绑定,主要负责关联语义树与Flutter Engine。Flutter维护了一个 semantic tree(语义树),页面构建的时候会根据各Widget的语义描述构建一棵 semantic tree。如在Image组件中配置 semanticLabel 语义内容,用户在IOS/Android手机开启无障碍功能时,触摸到该 Image 时通过语义树查找到对应的语义描述交给Flutter Engine,实现读屏等功能。对应Semantics widget,给子Widget定义语义,一些安卓自动化无法识别flutter上的widget,通过Semantics 定义语义就可以识别出来了

PaintingBinding

监听系统字体变化事件

ServicesBinding

  @override
  void initInstances() {
    super.initInstances();
    _instance = this;
    
    // 构建一个用于platform与flutter层通信的 BinaryMessenger
    _defaultBinaryMessenger = createBinaryMessenger();
    
    // 设置window监听回调,处理platform发送的消息
    window.onPlatformMessage = defaultBinaryMessenger.handlePlatformMessage;
    initLicenses();
    
    // 设置处理platform发送的系统消息的 Handler
    SystemChannels.system.setMessageHandler(handleSystemMessage);
    
    // 设置AppLifecycleState生命周期回调
    SystemChannels.lifecycle.setMessageHandler(_handleLifecycleMessage);
    
    // AppLifecycleState 为 resumed 和 inactive 时才允许响应Vsync信号进行绘制
    readInitialLifecycleStateFromNativeWindow();
  }

ServicesBinding的初始化的工作主要是两个:

  • platform与flutter层通信相关服务的初始化(比如读取asset内的资源就是通过defaultBinaryMessenger 也是内部默认的channel使用的消息对象 )
  • 注册监听了flutter app的生命周期变化事件,根据生命周期状态决定是否允许发起绘制任务

SchedulerBinding

绘制调度绑定,绘制渲染流程会详细分析,也可关注文后的绘制流程时序图

GestureBinding

手势事件绑定,主要处理触屏幕指针事件的分发以及事件最终回调处理。

绑定根节点(scheduleAttachRootWidget)

  @protected
  void scheduleAttachRootWidget(Widget rootWidget) {
    Timer.run(() {
      // 将传入的Widget绑定RenderView根节点上
      attachRootWidget(rootWidget);
    });
  }

attachRootWidget源码:

  void attachRootWidget(Widget rootWidget) {
    _readyToProduceFrames = true;
    _renderViewElement = RenderObjectToWidgetAdapter(
      container: renderView,
      debugShortDescription: '[root]',
      child: rootWidget,
    ).attachToRenderTree(buildOwner, renderViewElement as RenderObjectToWidgetElement);
  }

先是通过传入的 rootWidget 及 RenderView 实例化了一个RenderObjectToWidgetAdapter对象,而RenderObjectToWidgetAdapter是继承自RenderObjectWidget,即创建了Widget树的根节点。继续调用 attachToRenderTree:

  RenderObjectToWidgetElement attachToRenderTree(BuildOwner owner, [ RenderObjectToWidgetElement element ]) {
    if (element == null) {
      owner.lockState(() {
      
        // 创建了一个RenderObjectToWidgetElement实例作为element tree的根节点
        element = createElement();
        assert(element != null);
        
        // 绑定BuildOwner
        element.assignOwner(owner);
      });
      
      // 标记需要构建的element,并rebuild
      owner.buildScope(element, () {
        element.mount(null, null);
      });

      SchedulerBinding.instance.ensureVisualUpdate();
    } else {
      element._newWidget = this;
      element.markNeedsBuild();
    }
    return element;
  }
@override
void mount(Element parent, dynamic newSlot){
………
_rebuild();
} 



void _rebuild(){
………
_child = updateChild(_child, widget.child. _rootChildSlot);
………
}

}
@override
  RenderObjectToWidgetElement createElement() => RenderObjectToWidgetElement(this);

attachToRenderTree 中通过 createElement() 创建了一个RenderObjectToWidgetElement 实例作为 element tree 的根节点,并绑定BuildOwner,通过 BuildOwner 构建需要构建的 element。
在mount函数这里会触发_rebuild();在_rebuild()里面我们看到了updateChild,updateChildl里有调用inflateWidget方法,inflateWidget这个函数,在这个函数里面就会触发StatelessWidget和StatefulWidget的 createElement去创建element ,element又会去调用对应类的mount函数,经过一系列的流程之后,又会回到inflateWidget这个函数中,再次触发新的mount函数,形成一个层层调用,不断创建parentElement到childElement的过程,这个过程完成了element tree的构建。

绘制热身帧(scheduleWarmUpFrame)

  void scheduleWarmUpFrame() {
    if (_warmUpFrame || schedulerPhase != SchedulerPhase.idle)
      return;

    _warmUpFrame = true;
    Timeline.startSync('Warm-up frame');
    final bool hadScheduledFrame = _hasScheduledFrame;
    Timer.run(() {
      assert(_warmUpFrame);
      handleBeginFrame(null);
    });
    Timer.run(() {
      assert(_warmUpFrame);
      handleDrawFrame();
      resetEpoch();
      _warmUpFrame = false;
      if (hadScheduledFrame)
        scheduleFrame();
    });

    lockEvents(() async {
      await endOfFrame;
      Timeline.finishSync();
    });
  }

热身帧是通过handleBeginFrame、handleDrawFrame这两个回调来进行绘制流程。handleBeginFrame处理动画相关逻辑,动画回调后并不立即执行动画,而是改变了animation.value,并调用setSate()来发起绘制请求。动画的过程就是在 Vsync 信号到来时根据动画进度计算出对应的 value,而对应的 Widget 也会随着 animation.value 的变化而重建,从而形成动画,和Android的属性动画原理差不多。handleBeginFrame处理完后,会优先处理microTask任务队列。然后才是event Task,window.onDrawFrame(),对应SchedulerBinding.handleDrawFrame()。(Timer任务会加入到event queue,flutter的事件处理机制是优先处理 micro queue 中任务)

  void handleDrawFrame() {
    assert(_schedulerPhase == SchedulerPhase.midFrameMicrotasks);
    Timeline.finishSync(); // end the "Animate" phase
    try {
      // 处理Persistent类型回调,主要包括build\layout\draw流程
      _schedulerPhase = SchedulerPhase.persistentCallbacks;
      for (final FrameCallback callback in _persistentCallbacks)
        // 注释1
        _invokeFrameCallback(callback, _currentFrameTimeStamp);

      // 处理Post-Frame回调,主要是状态清理,准备调度下一帧绘制请求
      _schedulerPhase = SchedulerPhase.postFrameCallbacks;
      final List localPostFrameCallbacks =
          List.from(_postFrameCallbacks);
      _postFrameCallbacks.clear();
      for (final FrameCallback callback in localPostFrameCallbacks)
        _invokeFrameCallback(callback, _currentFrameTimeStamp);
    } finally {
    
      // 处理完成,设置状态为idle
      _schedulerPhase = SchedulerPhase.idle;
      Timeline.finishSync(); // end the Frame
      assert(() {
        if (debugPrintEndFrameBanner)
          debugPrint('▀' * _debugBanner.length);
        _debugBanner = null;
        return true;
      }());
      _currentFrameTimeStamp = null;
    }
  }
  // RendererBinding
  void _handlePersistentFrameCallback(Duration timeStamp) {
    drawFrame();
    _mouseTracker.schedulePostFrameCheck();
  }

  void drawFrame() {
    assert(renderView != null);
    // 布局
    pipelineOwner.flushLayout();
    // 更新 RenderObject 中需要绘制的内容
    pipelineOwner.flushCompositingBits();
    // 绘制
    pipelineOwner.flushPaint();
    if (sendFramesToEngine) {
      // 产生这一帧的数据Scene,由window.render交给Engine,最终显示到屏幕(发送数据到GPU)。
      renderView.compositeFrame();
      // 将语义树发送到操作系统
      pipelineOwner.flushSemantics();
      _firstFrameSent = true;
    }
  }
// WidgetsBinding
void drawFrame() {
   ...
   
   try {
    if (renderViewElement != null)
      //调用BuildOwner.buildScope开始构建
      buildOwner.buildScope(renderViewElement);
      
    //调用RendererBinding.drawFrame,开始布局、绘制阶段。
    super.drawFrame();
    
    //从element tree中移除不需要的element,unmount
    buildOwner.finalizeTree();
  } finally {
     ...
  }
}
绘制时序.png

SchedulerBinding.scheduleWarmUpFrame
-> SchedulerBinding.handleBeginFrame 处理动画
-> SchedulerBinding.handleDrawFrame
-----> WidgetBinding.drawFrame 通过 buildOwner 构建组件
-----> RendererBinding.drawFrame 通过 pipelineOwner 完成组件布局和绘制
-----> renderView.compositeFrame 发送 Scene 到GPU

启动调用时序.png

欢迎拍砖,交流!

你可能感兴趣的:(Flutter 启动流程)