Flutter runApp到渲染上屏分析详解

 更新时间:2022年11月22日 15:32:30   作者:WeninerIo  
这篇文章主要为大家介绍了Flutter runApp到渲染上屏分析详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

起源

flutter作为一个跨平台的框架,在绘制上体现出了它跨平台的良好性能.那么,它是如何从runApp()后 绘制上屏的呢?本文将与你一起去探索这一过程.

ps: 为了思维不中断, 本文仅对整体流程作分析,不会深入分析具体实现

我们运行一个flutter app ,入口一定是从runApp() 中进行的. 那么flutter 在runApp() 中做了哪些处理呢? 首先,我们从runApp() 这个函数聊起.它是一个需要传入Widget 的函数.而传入的Widget ,即首屏渲染所需的Widget.

在此我们应该知道这个概念, 即widget 是flutter 中用来描述ui如何绘制的配置文件,去形容一个组件在整体中的位置、大小.

那么不难推断出.在runApp() 的过程中,如果Widget是绘制的配置文件. 那么手势注册、桢调度等都应该是在此时注册的. 带着这样的推断我们去源码中找答案.

分析准备

void runApp(Widget app) {
  WidgetsFlutterBinding.ensureInitialized()
  // 这里解释下:
  // ..是flutter中的级联运算符
  // 可以同一个对象上连续调用多个对象的变量或方法
    ..scheduleAttachRootWidget(app)
    ..scheduleWarmUpFrame();
}

在runApp() 中可以看到, 这里实际上也就是调用了三个方法,以下我们对每个方法进行刨析.

ensureInitialized

从字面意思看,这是为了确保已经初始化而调用的方法.它的作用是为了返回WidgetsBinding的对象.如果了解单列模式的话,会发现这么写实际上就是一个单列模式.

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

这里我们去挖掘一下WidgetsFlutterBinding内部的构造函数在初始化时做了什么? 它是继承BingingBase的, 我们进入BingingBase中浅看一下大概的实现, Timeline 和assert这部分代码我们可以忽略.

ps: assert 在release代码中不会执行

也就是实际上的结构是这样的

 BindingBase() {
    initInstances();
    initServiceExtensions();
  }
  • initInstances() 方法是为了绑定初始化实例和其他的一些状态.
  • initServiceExtensions() 方法是为了绑定初始化服务

这里我们回过头来看WidgetsFlutterBinding它的一些实现接口, 顺序依次是:

接口解释
GestureBinding实现点击命中测试
SchedulerBinding引入了帧的概念
ServicesBinding提供对插件的访问
PaintingBinding解码图像
SemanticsBinding语义树
RendererBinding处理render tree
WidgetsBinding处理widget tree

内部的具体实现这里不再赘述,后续会逐章对这些进行分解、解释.这里只是去分析整体的流程. 也就是说, 在这里我们完成了对app系统的初始化、推动界面的绘制,获取手势等等.

scheduleAttachRootWidget

在一系列服务注册完之后,我们需要把当前的root widget 挂载到树上,

  void scheduleAttachRootWidget(Widget rootWidget) {
    Timer.run(() {
      attachRootWidget(rootWidget);
    });
  }

在attachRootWidget 的方法中, 我们构建了RenderObjectToWidgetAdapter 的对象. 通过RenderObjectToWidgetAdapter 当作Element 和RenderObject 之间的桥梁,

{
    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();
    }
}

同时,这里 根据renderViewElement 有没有赋值来判断是否是第一次加载.如果是第一次加载页面,会通知界面去刷新ui

scheduleWarmUpFrame

这个方法从字面意思来看 应该是在界面启动时去执行的一些方法. 首先,我们看一下它的一些引用路径.发现一共有三个地方的代码都引用了这个方法

可以看到调用的三个地方分别是:

  • allowFirstFrame()
  • performReassemble()
  • runApp()

好家伙,这不都是类似于绘制的入口函数? 因此,我们可以推断这里就是一些绘制时初始化时候必须执行的一些代码.

{
    // 这里通过伪代码简要了解一下大致实现
    // 
    if (_warmUpFrame || schedulerPhase != SchedulerPhase.idle) return;
    _warmUpFrame = true;
    // 这里把源代码提前了,由于handle*()的代码都是通过Timer.run执行的,实际上是
    // 一种异步执行,会在下一帧去调用
    lockEvents(() async {
      await endOfFrame;
      timelineTask.finish();
    });
    // 开始帧回调
    handleBeginFrame(null);
    // 新帧回调处理
    handleDrawFrame();
    // 这里和热重载相关
    resetEpoch();
    _warmUpFrame = false;
    // 
    if (hadScheduledFrame) scheduleFrame();
}

总结

总结一下, runApp() 通过

  • 注册各种服务
  • 注册ui
  • 绘制上屏

最终在屏幕上呈现出ui,其中还有如PipelineOwner、BuildOwner等等非常重要的api,这里暂且不表. 后续我们单章详细介绍,希望这一次与你一起阅读的思路可以帮你一起思考启动的流程.

以上就是Flutter runApp到渲染上屏分析详解的详细内容,更多关于Flutter runApp渲染上屏的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:

相关文章

  • Android开发之无痕过渡下拉刷新控件的实现思路详解

    Android开发之无痕过渡下拉刷新控件的实现思路详解

    下拉刷新效果功能在程序开发中经常会见到,今天小编抽时间给大家分享Android开发之无痕过渡下拉刷新控件的实现思路详解,需要的朋友参考下吧
    2016-11-11
  • Kotlin Flow数据流的3种使用场景详解

    Kotlin Flow数据流的3种使用场景详解

    这篇文章主要为大家详细介绍了Kotlin中Flow数据流的几种使用场景,文中的示例代码讲解详细,具有一定的借鉴价值,需要的可以参考一下
    2023-04-04
  • Android实现检测实体按键事件并屏蔽

    Android实现检测实体按键事件并屏蔽

    这篇文章主要介绍了Android实现检测实体按键事件并屏蔽 ,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • Android中的android:layout_weight使用详解

    Android中的android:layout_weight使用详解

    layout_weight的作用是设置子空间在LinearLayout的重要度(控件的大小比重)。layout_weight的值越低,则控件越重要,下面为大家介绍下具体的使用方法
    2013-06-06
  • Android SRT字幕文件基础操作讲解

    Android SRT字幕文件基础操作讲解

    这篇文章主要介绍了Android SRT字幕文件基础操作,SRT的数据格式是通过以上单个数据节点可以提供一个大致的思路是:先定位一个数据节点的固定格式,然后将一行一行的读取到数据
    2023-01-01
  • Android中判断是否联网实现代码

    Android中判断是否联网实现代码

    这篇文章主要介绍了Android中判断是否联网实现代码,本文直接给出实现代码,需要的朋友可以参考下
    2015-06-06
  • RecyclerView实现横向滚动效果

    RecyclerView实现横向滚动效果

    这篇文章主要为大家详细介绍了RecyclerView实现横向滚动效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-01-01
  • Android7.0 工具类:DiffUtil详解

    Android7.0 工具类:DiffUtil详解

    这篇文章主要介绍了Android7.0 工具类:DiffUtil的相关资料,并附实例代码,和实现效果图,需要的朋友可以参考下
    2016-09-09
  • 浅谈Android PathMeasure详解和应用

    浅谈Android PathMeasure详解和应用

    本篇文章主要介绍了浅谈Android PathMeasure详解和应用,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-01-01
  • Android组件DrawerLayout仿网易新闻v4.4侧滑菜单

    Android组件DrawerLayout仿网易新闻v4.4侧滑菜单

    这篇文章主要为大家详细介绍了Android组件DrawerLayout仿网易新闻v4.4侧滑菜单,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-01-01

最新评论