likes
comments
collection
share

Flutter渲染原理系列之runApp执行流程

作者站长头像
站长
· 阅读数 18

Flutter渲染原理系列之runApp执行流程

前言

一、runApp

---->[1/5main.dart]----
void main() {
  runApp( const MyApp());
}

---->[2/5 src/widgets/binding.dart]----
void runApp(Widget app){
    WidgetsFlutterBinding.ensureInitialized()
      ..scheduleAttachRootWidget(app)
      ..scheduleWarmUpFrame();
}

1、Flutter应用的执行始于main.dart文件中的main函数,这是Dart程序的入口点。

2、runApp方法,位于src/widgets/binding.dart中的全局方法,其参数为一个Widget对象,该Widget将成为应用的根组件

二、WidgetsFlutterBinding

---->[3/5 src/widgets/binding.dart]----
/// 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, SchedulerBinding, ServicesBinding, 
    PaintingBinding, SemanticsBinding,RendererBinding, 
    WidgetsBinding {
    
    //唯一的静态方法
    static WidgetsBinding ensureInitialized() {
      if (WidgetsBinding._instance == null) {
        WidgetsFlutterBinding();
      }
      return WidgetsBinding.instance;
    }
}

1、是Flutter框架中的一个核心类,它扮演着桥梁的角色,连接Dart层的Widget框架和底层的Flutter引擎

2、继承自BindingBase,并且混入了七大xxxBinding,只有一个静态方法ensureInitialized,该方法返回WidgetsBinding单例对象。

三、BindingBase

abstract class BindingBase {
  BindingBase() {
    //...
    initInstances();
    //...
  }

ui.PlatformDispatcher get platformDispatcher => ui.PlatformDispatcher.instance; 

此抽象类中需要重点关注两点:

1、在构造函数中会调用mixin的七大xxxBinding绑定类各自initInstances方法。

2、platformDispatcher(平台分发器),是Flutter中的一个核心接口,用于处理与平台(如iOSAndroid)交互的事件。它是Flutter引擎框架之间的桥梁,使得框架能够访问和响应来自引擎的事件,如输入事件(触摸、鼠标、键盘等)、画面帧绘制请求等。

四、WidgetsBinding

---->[4/5 src/widgets/binding.dart]----
///The glue between the widgets layer and the Flutter engine.
mixin WidgetsBinding on BindingBase, ServicesBinding,SchedulerBinding, 
GestureBinding, RendererBinding, SemanticsBinding {

  @override
  void initInstances() {
    super.initInstances();
    _instance = this;
    _buildOwner = BuildOwner();
    buildOwner!.onBuildScheduled = _handleBuildScheduled;
    //...
  }
  
  /// Schedules a [Timer] for attaching the root widget.
  @protected
  void scheduleAttachRootWidget(Widget rootWidget) {
    Timer.run(() {
      attachRootWidget(rootWidget);
    });
  }

  /// Takes a widget and attaches it to the [renderViewElement], creating it if necessary.
  void attachRootWidget(Widget rootWidget) {
    final bool isBootstrapFrame = renderViewElement == null;
    _readyToProduceFrames = true;
    _renderViewElement = RenderObjectToWidgetAdapter<RenderBox>(
      container: renderView,
      debugShortDescription: '[root]',
      child: rootWidget,
    ).attachToRenderTree(buildOwner!, renderViewElement as RenderObjectToWidgetElement<RenderBox>?);
    if (isBootstrapFrame) {
      SchedulerBinding.instance.ensureVisualUpdate();
    }
  }
}

1、WidgetsFlutter引擎之间的粘合剂,用来连接Widgetengine

2、该类创建了BuildOwner对象,它是构建期间(build)的管理者,主要负责管理Widget的重建,并且设置了onBuildScheduled回调。

3、在scheduleAttachRootWidget方法中开启一个任务,主要用于将应用程序的根Widget附加到渲染树中,渲染前的准备。

4、attachRootWidget方法的主要作用是将根rootWidget绑定到渲染树rendeViewElement中。这里的renderView是在初始化RenderBinding时创建的RenderView实例,也是渲染树的根节点

五、RenderObjectToWidgetAdapter

---->[5/5src/widgets/binding.dart]----
/// A bridge from a [RenderObject] to an [Element] tree.
class RenderObjectToWidgetAdapter<T extends RenderObject> extends RenderObjectWidget {

  RenderObjectToWidgetAdapter({
    this.child,
    required this.container,
    this.debugShortDescription,
  }) : super(key: GlobalObjectKey(container));

  @override
  RenderObjectToWidgetElement<T> createElement() => RenderObjectToWidgetElement<T>(this);

  RenderObjectToWidgetElement<T> attachToRenderTree(BuildOwner owner, [ RenderObjectToWidgetElement<T>? element ]) {
    if (element == null) {
      owner.lockState(() {
        element = createElement();
        assert(element != null);
        element!.assignOwner(owner);
      });
      owner.buildScope(element!, () {
        element!.mount(null, null);
      });
    } else {
      element._newWidget = this;
      element.markNeedsBuild();
    }
    return element!;
  }
}

1、此组件是一个特殊的RenderObjectWidget,它在Widget层渲染层之间充当桥梁,将Widget树上的节点映射到渲染树上的RenderObject节点

2、createElement方法会实例化该类型元素,并将组件自身作为入参,返回一个RenderObjectToWidgetElement对象。

3、attachToRenderTree方法的主要作用是将Widget树中的根Widget与渲染树中的根RenderObject进行关联。

attachToRenderTree方法的主要功能:

  • 构建Element树:
    • 该方法首先会创建一个新的RenderObjectToWidgetElement,用于将RenderObjectWidget连接起来。它会从当前的RenderObjectToWidgetAdapter实例中获取rootWidget,并使用此rootWidget创建Element树的根Element
  • 关联RenderObject
    • 同时,还会关联RenderObject树的根节点。这意味着它会设置RenderObject树中的根节点Element树中的根Element相对应。
  • 构建和更新Element树:
    • 它会调用BuildOwnerlockState方法来保证在构建过程中没有状态更改,然后创建Element树。如果之前已经有Element树存在,那么会更新现有的Element树,以反映任何在Widget树中的变化。
  • 触发布局绘制
    • Element树建立或更新完毕后,它会触发渲染树的布局和绘制过程,以确保屏幕上的内容与新的Widget树匹配。

attachToRenderTree方法执行完成后,会根据Widget生成对应的Element树和RenderObject树。此阶段对应于渲染流水线的build阶段。

六、scheduleWarmUpFrame

void scheduleWarmUpFrame() {
  Timer.run(() {
    handleBeginFrame(null);
  });
  Timer.run(() {
    handleDrawFrame();
  });
}

1、安排一个帧尽快运行,而不是等待引擎根据系统Vsync信号请求帧。

2、此方法中开启了两个任务,从此就进入了渲染流水线中的layout阶段和paint阶段。

3、至此,runApp里调用的最后一个函数的执行完成。

七、总结

runApp执行流程的主要步骤如下:

1、初始化

  • runApp被调用时,首先会检查WidgetsFlutterBinding实例是否存在,若无则会创建该实例。

2、设置root widget

  • runApp接受一个Widget作为参数,该Widget将成为应用程序的根Widget

3、构建Element树:

  • runApp会创建一个Element树的根节点,这通常是一个ComponentElement。这个过程涉及构建一个与Widget树对应的Element树,其中每个Widget都有一个对应的Element

4、创建RenderObject树:

  • 接下来,runApp会构建一个RenderObject树,这是实际负责布局绘制的树。

5、初始化Binding

  • runApp会调用WidgetsFlutterBinding.instance.attachRootWidget方法,这将触发一系列初始化操作,包括设置SchedulerBindingPaintingBinding,以及初始化SemanticsBindingGesturesBinding

6、触发构建布局

  • runApp会请求一个新的帧,这会触发Element树的构建过程,接着是RenderObject树的布局和绘制。这通常涉及调用build方法来创建Widget的子树,然后调用layoutpaint方法来安排和绘制RenderObject

7、事件循环:

  • 一旦应用程序的初始布局绘制完成,事件循环将开始监听和处理各种事件,如用户输入和定时器回调。runApp之后的执行将由这些事件驱动

8、生命周期管理

  • runApp还涉及到生命周期管理,例如,在StatefulWidget的情况下,initState方法会在Widget第一次构建时被调用。

总而言之,runApp不仅启动了应用程序的初始化,还建立了WidgetElementRenderObject之间的联系,从而使得应用程序的UI能够在屏幕上正确地呈现和响应用户交互。

码字不易,记得关注 + 点赞 + 收藏

转载自:https://juejin.cn/post/7399984522094428187
评论
请登录