IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Flutter框架分析(七)-relayoutBoundary -> 正文阅读

[移动开发]Flutter框架分析(七)-relayoutBoundary

1. 前言

Flutter框架分析(四)-RenderObject一文中,我们简单介绍了RenderObject中一个重要成员变量:RelayoutBoundary。下面我们简单回顾下RelayoutBoundary的主要作用。
当一个组件的大小被改变时,其parent的大小可能也会被影响,因此需要通知其父节点。如果这样迭代上去,需要通知整棵RenderObject Tree重新布局,必然会影响布局效率。因此,Flutter通过RelayoutBoundaryRenderObject Tree分段,如果遇到了RelayoutBoundary,则不去通知其父节点重新布局,因为其大小不会影响父节点的大小。这样就只需要对RenderObject Tree中的一段重新布局,提高了布局效率。
那么,RelayoutBoundary是怎么实现将RenderObject Tree分段的呢?本文将通过源码来剖析RelayoutBoundary的工作原理。

2. 源码解析

Flutter中,如果Widget有更新,需要重新布局,Framework会将需要布局的RenderObject加入PipelineOwner的_nodesNeedingLayout中,然后当下一个VSync信号来临时,Framework会遍历_nodesNeedingLayout,对其中的每一个RenderObject重新进行布局,遍历_nodesNeedingLayout的函数源码如下:

void flushLayout() {
  try {
    // TODO(ianh): assert that we're not allowing previously dirty nodes to redirty themselves
    while (_nodesNeedingLayout.isNotEmpty) {
      final List<RenderObject> dirtyNodes = _nodesNeedingLayout;
      _nodesNeedingLayout = <RenderObject>[];
      for (final RenderObject node in dirtyNodes..sort((RenderObject a, RenderObject b) => a.depth - b.depth)) {
        if (node._needsLayout && node.owner == this)
          node._layoutWithoutResize();
      }
    }
  } finally {
  }
}

其中,_layoutWithoutResize会调用RenderObjectperformLayout函数,实现该RenderObject的重新布局。
以上流程的示意图如下:

image.gif

由上述逻辑可知,当Widget有更新,需要重新布局时,加入_nodesNeedingLayout的元素的多少直接关系到需要重新布局元素的多少,如果能将尽可能少的RenderObject加入_layoutWithoutResize,即可尽可能提高布局效率。这就是设计RelayoutBoundary的核心思路。
下面我们来看什么时候会将RenderObject添加进_nodesNeedingLayout。从源码可以看到,添加进_nodesNeedingLayout有两个地方:

  • 初始化RenderView的时候,源码如下:
void scheduleInitialLayout() {
  _relayoutBoundary = this;
  owner._nodesNeedingLayout.add(this);
}

本函数只在Flutter初始化的时候调用一次。

  • RenderObject标记自己需要重新布局的时候,源码如下:
void markNeedsLayout() {
  if (_needsLayout) {
    return;
  }
  if (_relayoutBoundary != this) {
    markParentNeedsLayout();
  } else {
    _needsLayout = true;
    if (owner != null) {
      owner._nodesNeedingLayout.add(this);
      owner.requestVisualUpdate();
    }
  }
}

那本函数的调用时机是什么呢?主要有以下几种:

  • 子节点变动,例如attachdetach
  • 自身布局变化,例如Size变化。
    Flutter初始化进行第一次布局,每个RenderObject均需要布局,因此无优化空间,本文主要关注对重新布局的优化,即对markNeedsLayout的调用。接下来我们分析markNeedsLayout的调用链。其流程图如下:

image.gif

可见,在一个RenderObject调用markNeedsLayout函数后,如果其本身不是_relayoutBoundary,则会通过markParentNeedsLayout函数调用到parentmarkNeedsLayout函数,从而形成递归调用,直到找到最近的一个是_relayoutBoundary的上级节点,才会停止递归,并将该节点加入_nodesNeedingLayout。因此,通过_relayoutBoundary,FlutterRenderObject Tree划分成了数段,当位于某段的RenderObject需要重新布局时,只会更新该段及其下的RenderObject,而不是整个RenderObject Tree。示意图如下:

image.gif

那么,什么时候会将RenderObject设置为RelayoutBoundary呢?满足以下4种情况之一时,会将自身设置为RelayoutBoundary

  • parentUsesSize = false:父节点的布局不依赖当前节点的大小。
  • sizedByParent = true:当前节点大小由父节点决定。
  • constraints.isTight:大小为确定的值,即宽高的最大值等于最小值。
  • parent is not RenderObject:如果父节点不是RenderObject,子节点layout变化不需要通知父节点更新。

以上条件很好理解,例如parentUsesSize = false,此时父节点的布局不依赖当前节点的大小,那当前节点布局更新自然不需要通知父节点,因此可以将其作为一个RelayoutBoundary

3. 小结

本文首先介绍了RelayoutBoundary的作用,然后结合源码分析了RelayoutBoundary的作用原理,其重点如下:

  1. RelayoutBoundary通过减少待布局节点列表数量(加入_nodesNeedingLayout)的方式优化节点更新时的布局效率。
  2. RelayoutBoundary的设置条件包括以下4种:
  • parentUsesSize = false
  • sizedByParent = true
  • constraints.isTight
  • parent is not RenderObjec

4. 参考文档

如何在Flutter上实现高性能的动态模板渲染

5. 相关文章

Flutter框架分析(一)–架构总览
Flutter框架分析(二)-- Widget
Flutter框架分析(三)-- Element
Flutter框架分析(四)-RenderObject
Flutter框架分析(五)-Widget,Element,RenderObject树
Flutter框架分析(六)-Constraint
Flutter框架分析- Parent Data
Flutter框架分析 -InheritedWidget

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-07-07 00:02:59  更:2021-07-07 00:04:07 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/5 6:42:11-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码