资讯

精准传达 • 有效沟通

从品牌网站建设到网络营销策划,从策略到执行的一站式服务

flutter更新频率,Flutter性能优化

Flutter局部刷新方法

Flutter中Widget分为StatefulWidget和StatelessWidget,分别为动态视图和静态视图,视图的更新需要调用StatefulWidget的setState方法,这会遍历调用子Widget的build方法。当一个主页面比较复杂时,会包含多个widget,如果直接调用setState,会遍历所有子Widget的build,这是非常不必要的性能开销,有没有单独刷新指定Widget的方式呢?这个时候就要用到GlobalKey了。

成都创新互联是一家专注于网站设计制作、成都网站建设与策划设计,凌源网站建设哪家好?成都创新互联做网站,专注于网站建设10余年,网设计领域的专业建站公司;建站业务涵盖:凌源等地区。凌源做网站价格咨询:18980820575

一个StatefulWidget包含一个Button,一个Text,通过点击Button调用主Widget的setState方法,刷新Text,示例如下:

同样一个StatefulWidget包含一个多个Text和Button,点击Button我们只需要刷新指定的Text,通过GlobalKey的方式,实现如下:

主Widget,包含一个需要更新的TextWidget和一个不需要更新的Text

需要单独更新的Widget

传递事件的Button

这样点击Button就只会更新指定的TextWidget了,效果如下:

这只是一个简单的例子,在实际开发中为了页面刷新的高效率,模块化封装非常重要。很多情况下都只需要局部刷新,而不是重构整个视图。所以Globalkey的运用在项目中需要熟练掌握

Flutter的setState(状态刷新)

Flutter有两个常用的状态类:

标记为dirty,执行的markNeedsBuild,定义在Element类中:

当前Element节点被标记为dirty,同时调用owner的scheduleBuildFor方法:

将element元素添加到全局的“脏”链表里。

BuildOwner用来管理哪些需要更新的Widget。这个owner最开始被初始化的地方在WidgetsBinding的initInstances方法中,随后初始化了onBuildScheduled方法,对应执行的是_handleBuildScheduled,定义在WidgetsBinding类中:

ensureVisualUpdate 方法定义在SchedulerBinding类中:

在提交下一帧绘制的时候会调用到scheduleFrame方法,提交给引擎绘制,看看scheduleFrame方法,也定义在SchedulerBinding类中:

提交给引擎绘制之后,会收到onDrawFrame的回调,最终执行到_handleDrawFrame方法中,对应的是handleDrawFrame方法,定义在SchedulerBinding类中:

在RendererBinding的initInstances方法中添加了一个回调到这个List中,对应的是RenderBinding的drawFrame方法,对应的节点进行绘制渲染操作。

WidgetsBinding中的drawFrame方法:

看看这里的buildScope方法,定义在BuildOwner方法中。在上面 scheduleBuildFor 方法介绍中有提到:"scheduleBuildFor 是把一个 element 添加到 _dirtyElements 链表,以便当[WidgetsBinding.drawFrame]中调用 buildScope 的时候能够重构 element。onBuildScheduled()是一个 BuildOwner 的回调"。在 drawFrame 中调用 buildOwner.buildScope(renderViewElement)更新 elements。

_dirtyElements列表在遍历的过程中执行rebuild方法,此时将所有标记为dirty的Element节点依次执行rebuild,preformRebuild,build,updateChild,update方法,执行界面更新。完成build,update操作完成之后,后续会将需要绘制的RenderObject添加到需要layout的列表中,等待绘制渲染。所有绘制完成之后将_dirtyElments列表清空,_inDirtyList标记位置为false。

提交给引擎绘制渲染

看看super.drawFrame(),这里就执行到了RendererBinding类中,定义如下:

这里就是将最终需要绘制渲染的画面提交给引擎的地方了,绘制完成之后就在界面显示更新后的视图了。

Flutter中的StatefulWidget及其生命周期

状态可变的 widget 。

通过其类的定义能够看到 StatefulWidget 配置 StatefulElement 。

State 是 StatefulWidget 的内部逻辑与状态,由 StatefulWidget 的 createState 创建。

StatefulWidget 实例本身是不可变的, 但是 StatefulWidget 将其可变的状态,存储在与之关联的 State 对象中。

不管什么时候,只要在树中 mount 一个新的 StatefulElement ,必然需要注入一个 StatefulWidget ,注入一个 StatefulWidget 时, framework 都会调用一次 createState 方法。

其实,在 StatefulElement 构造的时候,就会调用 createState ,创建 _state 对象,( _state 是 StatefulElement 的变量)并且在 StatefulElement 的初始化方法中为 _state 关联当前的 StatefulElement 和用以配置 StatefulElement 的 StatefulWidget 。

StatefulElement 初始化方法如下:

这意味着如果 StatefulWidget 被插入到树中的多个位置,则会有多个 State 对象分别与它们关联。

关于此类的定义如下:

描述: 重写此方法以执行初始化。

场景: 如果 State 的 build 方法依赖于本身可以改变状态的对象时。(例如 ChangeNotifier 或 Stream ,或者可以订阅并接收通知的其他对象)正确的方式是:

注意点: 此方法中不能使用 BuildContext.dependOnInheritedWidgetOfExactType 。但是此方法被调用后会立即调用 didChangeDependencies ,在 didChangeDependencies 可以使用 BuildContext.dependOnInheritedWidgetOfExactType 。

调用时机: StatefulElement ,首次插入树中时会调用此方法,在 build 方法调用之前调用。

描述: StatefulElement 通过此方法返回的 widget 并通过调用 updateChild 来更新自己。

调用时机: framework 调用此方法的几个不同的场景如下:

描述: StatefulElement 存在,并且符合 Widget.canUpdate 的情况下对 StatefulWidget 进行更新。

调用时机: 不论何时只要 StatefulElement 的配置 widget 改变的时候就会调用。

注意: didUpdateWidget 方法最终会调用 build 方法,因此在此方法中调用 setState 是多余的。如果重写此方法,请确保调用 super.didUpdateWidget(oldWidget) 。

调用时机: 当此 State 对象的依赖项( InheritedWidget )更改时调用。

描述: 用于开发阶段 hot reload 。

调用时机: hot reload 时调用,调用后 build 方法也将被调用。无需在此方法中做任何操作。

调用时机: 当 StatefulElement 从树中移除的时候会调用。

调用时机: 当 StatefulElement 从树中 unmount 的时候会调用。

StatefulWidget 用以配置 StatefulElement ,但在这两者之间的 State 承接了 StatefulElement 的生命周期,而 StatefulWidget 仅仅只是连接了 State 与 StatefulElement 的不可变的实例,因此 StatefulWidget 的生命周期,依赖于 StatefulElement ,而 State 却是其最简单直接的体现形式。

为了能更好的理解 StatefulWidget 的生命周期,我画了一张关于 State 、 StatefulElement 、 Component 、 Element 的关系图。

flutter检测当前剩余的时间

我想你想要的是:target.difference(DateTime.now()).toString().split('.')[0])

使用.split('.')[0]持续时间来去掉秒的分数。

其中target是DateTime对象。flutter计算给定小时的剩余时间,以秒为单位更新flutter,因此,时间以h:m:s为单位,例如,如果给定的时间是(6:27pm),我希望得到此结果(剩余时间02:21:02)。

打印结果:Text('Timeuntil${DateFormat.Hms().format(target)}');Text(target.difference(DateTime.now()).toString().split('.')[0])

flutter项目升级2.0过程填坑记录

在此之前先推荐看大佬的: 填坑指导

iOS需要注意:

1、flutter2.0要求cocoapods 升级到1.9.0

详情看这篇博客

2、原来flutter项目中的podfile文件是旧版本的ccocoapods了,删除podfile和对应的.lock,然后flutter项目重新运行使用它自动生成的podfile文件

3、安装CocoaPods

卸载cocoapods:sudo gem uninstall cocoapods

查看cocoapods版本:pod --version

指定版本安装:

sudo gem install -n /usr/local/bin cocoapods -v 1.9.3(新MacOS系统升级)

不指定版本安装

sudo gem install -n /usr/local/bin cocoapods

说明 :老项目sdk1.17.0===升级到2.0.1,当前所有操作基于win平台

到此为止环境已经准备妥当,正式进入项目修改。

所有的插件都要适配到空安全,插件是否支持均会有对应说明Null safety,适配过程不确定版本的话,可以使用dio: any,适配完事后再在pubspec.lock文件中查看具体的版本修改过来,实在有部分插件没有支持的,参考下面

部分插件在适配空安全的版本放弃维护了,得自行更新或寻找替代,如: flutter_swiper 变为 flutter_swiper_null_safety ,插件更新后要注意项目中的用法是否需要更新

2.1.1: 以前采用的是 provide 插件共享全局数据,现在变化为 provider ,用法改变, 点击参考 ,以防文章丢失,我重复一遍:

比如:

2.1.2: dio版本升级到4.0.0最新版后,部分用法改变

2.2.1

2.2.2

解决方案:

2.2.3

解决方案:

2.2.4

解决方案:

2.2.5

解决方案:

2.2.6

解决方案:

2.2.7

解决方案:

2.2.8

解决方案: child 换为sliver

2.2.8.1

解决方案: 项目目录下: android--app-build.gradle --minSdkVersion改为:18 或者19

2.2.8.2

解决方案: 在pubspec.yarm管理里面添加:publish_to

2.2.8.3

解决方案: video_player升级后字段发生了变化,initialized字段更换为:isInitialized(_controller.value.isInitialized)

2.2.8.4

解决方案:

2.2.8.5

解决方案:

2.2.8.6

解决方案: 方案一:删除ios目录下的Podfile.lock 文件然后重新运行 pod install命令

方案二:删除ios目录下的Podfile.lock与Podfile文件 重新运行flutter run或flutter build ios

方案三:删除ios目录,重新运行 flutter create . 命令,注意有"."这个符号不要忘记

2.2.8.7

这个报错一般对应的就是下面的报错,注意看后面的报错信息,看是哪个插件报错。

解决方案: 把Podfile的版本注释打开,改为platform :ios, '9.0' 或者是更高的版本

全局替换

1.将new List() 替换为[];

2.TextField的inputFormatters:[WhitelistingTextInputFormatter.digitsOnly] 替换为[FilteringTextInputFormatter.digitsOnly]

3.TextField的inputFormatters:[WhitelistingTextInputFormatter(RegExp("[a-z|A-Z|0-9]"))]替换为FilteringTextInputFormatter.allow(RegExp("[a-z|A-Z|0-9]"))

4.Stack组件中overflow: Overflow.visible改为 clipBehavior: Clip.none;overflow: Overflow.clip改为clipBehavior:Clip.hardEdge

5.ListWheelScrollView组件中clipToSize = false改为clipBehavior: Clip.none,clipToSize = true改为 Clip.hardEdge

6.TextField中maxLengthEnforced: true改为maxLengthEnforcement:MaxLengthEnforcement.enforced

7.FlatButton、RaisedButton、OutlineButton的变化: 官方参考

颜色的属性发生了变化,由原来的Color 变为了MaterialStatePropertyColor, 这是未了解决不同状态(pressed、hovered、focused、disabled)下按钮颜色的变化

例如

8.出现如下警告

9.showSnackBar报错误

解决方案: Scaffold换为ScaffoldMessenger

10.textSelectionColor弃用

解决方案:

11.charts_flutter升级后属性报错

解决方案:

12.flutter 真机调试无法访问网络,dio报错

解决方案:

android:

ios:

问题12完整参考


当前文章:flutter更新频率,Flutter性能优化
路径分享:http://www.cdkjz.cn/article/dscjihe.html
多年建站经验

多一份参考,总有益处

联系快上网,免费获得专属《策划方案》及报价

咨询相关问题或预约面谈,可以通过以下方式与我们联系

大客户专线   成都:13518219792   座机:028-86922220