在今天这篇文章中,我将着重介绍这两种类型的区别,从而帮我们更好地理解Widget,掌握不同类型Widget的正确使用时机。...当你所要构建的用户界面不随任何状态信息的变化而变化时,需要选择使用StatelessWidget,反之则选用StatefulWidget。...而,Flutter框架则会标记视图状态,更新UI。...与StatelessWidget通过父Widget完全控制UI展示不同,StatefulWidget的父Widget仅定义了它的初始化状态,而其自身视图运行的状态则需要自己处理,并根据处理情况及时更新UI...虽然Flutter内部通过Element层可以最大程度地降低对真实渲染视图的修改,提高渲染效率,而不是销毁整个RenderObject树重建。但,大量Widget对象的销毁重建是无法避免的。
下面是StatefulWidget的最佳实践: 尽量将需要该表状态的widget防止在子节点,这样在改变整个渲染树的时候就只需要更新一个widget即可,如果将其防止在父节点那么将会导致当前节点的整个子节点的...对于要重新使用的窗口小部件,要比创建新的(但配置相同的)窗口小部件更有效。将有状态部分分解为带有子参数的小部件是执行此操作的常用方法。 尽可能使用`const`小部件。...下面的例子显示了更通用的小部件`Bird`,它可以被赋予一种颜色和一个子widget,并且它有一些内部状态,可以调用一个方法来改变它。 按照惯例,窗口小部件构造函数仅使用命名参数。...,则框架将更新此[State]对象的[widget]属性以引用新Widget然后使用上一个Widget作为参数调用此方法。...didUpdateWidget:在widget重新构建时,framework会调用canUpdate来检测Widget树中同一位置的新旧节点,然后决定是否需要更新。
Widget的更新机制: Widget是不可变的,更新则意味着销毁+重建。...因此StatefulWidget并不是万金油,我们在实际开发中,要正确审视自己的视图展示需求,避免无谓的StatefulWidget使用,这是提高页面渲染效率最简单也最直接的手段。...我们可以通过初始化方法,接收父Widget传递过来的初始化UI配置参数,这些配置参数决定了Widget的最初配置效果 initState,会在State对象被插入视图树的时候调用,这个函数在State的生命周期中只会被调用一次...当状态数据发生变化时,我们总是通过调用这个方法告诉Flutter:“我这儿的数据变啦,请使用更新后的数据重建UI!”...如上图所示,左边部分展示了当父Widget状态发生变化时,父子双方共同的生命周期;而中间和右边部分则描述了页面切换时,两个关联的Widget的生命周期函数是如何响应的。
- Widget管理子Widget状态。 - 混合管理(父Widget和子Widget都管理状态)。 - 不同模块的状态管理。 - 如何决定使用哪种管理方法?...- 如果状态是有关界面外观效果的,例如颜色、动画,那么状态最好由Widget本身来管理。 - 如果某一个状态是不同Widget共享的则最好由它们共同的父Widget管理。...model和资源回收的问题 - 对不同场景下使用的provider做了优化和区分 - 支持异步状态管理和provider依赖注入 - 缺点 - 使用不当可能会造成性能问题...### 03.状态管理使用场景 - setState状态管理 - 适合Widget管理自己的状态,这种很常见,调用setState刷新自己widget改变状态。...:由于 Provider 会监听 Value 的变化而更新整个 context 上下文,因此如果 build 方法返回的 Widget 过大过于复杂的话,刷新的成本是非常高的。
所以,在大多数时候,可以认为 widget 就是一个控件,不必纠结于概念 Widget 的功能是 “描述一个 UI 元素的配置数据”,widget 并不是表示最终绘制在屏幕上的显示元素,正在代绘制屏幕上的是...这是因为同一个 Widget 可以被添加到 UI 树的不同部分,而真正渲染时,UI 树的每一个 Element 都会对应一个 Widget 对象 。...Echo Widget widget 的构造函数参数应使用命名参数,命名参数中的必要参数要添加 @required 标注,这样有利于静态代码分析器进行检查。...createState 来创建状态(State)对象 createState 用于创建 Stateful widget 相关的状态,他在 Stateful widget 的生命周期中可能会被多次调用...来检测 Widget 树中同一个位置的新旧节点,然后去确定是否需要更新,如果 widget.canUpdate 返回 true 则会调用此回调。
的使用这些问题诟病很多,而Riverpod,正是在Provider的基础上,探索出了一条心的状态管理之路。...这一次,"ref "不是作为构建方法的参数传递,而是作为ConsumerState对象的一个属性。...这是通过ref.read完成的 ❝只要有可能,最好使用 ref.watch 而不是 ref.read 或 ref.listen 来实现一个功能。...这一点很重要,因为默认情况下,监听一个Provider会监听整个对象的状态。但有时,一个Widget/Provider可能只关心一些属性的变化,而不是整个对象。...每当用户改变时,Riverpod将调用这个函数并比较之前和新的结果。如果它们是不同的(例如当名字改变时),Riverpod将重建Widget。
是有状态的组建在更新构建过程上会有一点稍微的不同,今天我们就来看下StatefulWidget是如何更新Widget,以及它是如何触发界面变更的。...Widget,但是StatefulWidget没有build方法,所以它只能使用State的build来构建Widget。...然后判断state状态如果是created而且此时的Element不为空(mounte实际上就是表示Element的状态) 执行传入的函数体 判断函数体返回是不是一个Future,如果是就抛异常提示处理...而scheduleBuildFor最终会调用onBuildScheduled来通知每个Element去构建Widget。...小结 StatefulWidget是由状态组建,我们可以使用setState方法来重新构建组建 StatefulWidget的Wdiget是通过State的Build方法构建的 setState方法将要重新构建的
而随着 Android 12 的推出,也带来了 Widget API 一些亟需改进的更新。...会使用链接账户来更新布局并对 Widget 进行更新。...,这就是新参数的使用方法。...如下图所示,用户可以通过拖动来任意更改 Widget 的尺寸,Widget 也会根据尺寸的不同而动态更新所要显示的内容。...那么如何做到让 Widget 随着尺寸的变化而动态更新显示内容呢,用如下代码举例,我们定义了三个不同的参数,分别包含最小支持宽度和高度,以及在此大小范围内对应的 RemoteView,系统会自动根据实际的尺寸而自动对
Flutter 通过控件树中的每个控件创建不同类型的渲染对象,组成渲染对象树。而渲染对象树在 Flutter 的展示过程分为四个阶段:布局、绘制、合成和渲染。...更新 Widget 的状态更新,主要由 3 个方法触发: setState、didchangeDependencies 与 didUpdateWidget。...setState:我们最熟悉的方法之一。当状态数据发生变化时,我们总是通过调用这个方法告诉 Flutter:“我这儿的数据变啦,请使用更新后的数据重建 UI!”...didUpdateWidget:当 Widget 的配置发生变化时,比如,父 Widget 触发重建(即父 Widget 的状态发生变化时),热重载时,系统会调用这个函数。...ListView控件 ListView 的构造函数 ListView.builder,则适用于子 Widget 比较多的场景。其中,itemExtent 并不是一个必填参数。
Flutter的widget是不可改变的因此不能直接更新,而必须使用Widget的状态。Flutter的widget分为有状态和无状态两种。...它们的核心特性是相同的,每一帧它们都会重新构建,不同之处在于有状态的Widget有一个State对象,它可以跨帧存储状态数据并恢复它。...Widget,当用户交互或数据发生变化时,Widget状态发生改变,调用State的 setState 方法通知它,而后State根据当前的状态信息,重新构建Widget tree 在Android中,...在Flutter中,一个自定义widget通常是通过组合其它widget来实现的,而不是继承 某些widget属性需要单个widget(child),而其它一些属性,如action,需要一组widgets...这是通过使用Isolates来完成的。是一个独立的执行线程,它运行时不会与主线程共享任何内存。这意味着你不能从该线程访问变量或通过调用setState来更新你的UI。
,提高渲染效率,而不是销毁整个渲染视图树重建。...与 StatelessWidget 通过父 Widget 完全控制 UI 展示不同,StatefulWidget 的父 Widget 仅定义了它的初始化状态,而其自身视图运行的状态则需要自己处理,并根据处理情况即时更新...更新 Widget 的状态更新,主要由 3 个方法触发:setState、didchangeDependencies 与 didUpdateWidget。这三个方法分别会在什么场景下调用。...setState:我们最熟悉的方法之一。当状态数据发生变化时,我们总是通过调用这个方法告诉 Flutter:“我这儿的数据变啦,请使用更新后的数据重建 UI!”...比如,App 的按钮,无论在什么场景下都需要背景图片资源、字体颜色、字号大小等,而所谓的主题切换只是在不同主题之间更新这些资源及配置集合而已。
虽然MyHomePage类也是Widget,但与MyApp类不同,它没有build方法返回Widget,而是多个createState方法返回_MyHomePageState对象,而build方法包含在这...而Flutter框架收到通知后,会执行Widget#build,根据新状态重建界面。 状态的更改一定要配合使用setState。...在这个函数中,通过调用setState更新_counter属性同时,也通知Flutter框架其状态发生变化。...为此,Flutter对此机制 5 优化 其框架内部会通过一个中间层收敛上层UI配置对底层真实渲染的改动,从而最大程度降低对真实渲染视图的修改,提高渲染效率,而不是上层UI配置变就要销毁整个渲染视图树重建...而Flutter采用声明式UI设计,只需描述当前UI状态(即State),不同UI状态的视觉变更由Flutter在底层完成。
在前面我们介绍各种各样的Widget,相信大家对Wiget的使用都已经有了自己的认识,今天我们就从底层角度看下Widget是如何工作,是什么支撑起了Wiget这个系统。...其实,Widget并不是我们真正看到的视图,背后究竟是什么?...如果想要把可变状态与Widget关联起来,可以使用StatefulWidget,StatefulWidget通过使用StatefulWidget.createState方法创建State对象,并将之扩充到...Element也可以理解为,Widget中额外的属性,可以用来存储Widget的状态和额外的值。...,而不是销毁整个渲染视图树重建。
真正的布局和大小计算等行为,都是在 RenderBox 上去实现的。 不同的 Widget 通过各自的 RenderBox 实现了“差异化”的布局效果。...如下图所示,所有的 RenderObject 子类都必须实现 paint 方法,并且该方法并不是给用户直接调用,需要更新绘制时,你可以通过 markNeddsPaint 方法去触发界面绘制。...那么,按照“国际流程”,在经历大小和布局等位置计算之后,最终 paint 方法会被调用,该方法带有两个参数: PaintingContext 和 Offset ,它们就是完成绘制的关键所在,那么相信此时大家肯定有个疑问就是...其实这里的问题还是在于 PaintingContext ,它有一个参数是 estimatedBounds ,而 estimatedBounds 正常是在创建时通过 child.paintBounds 赋值的...我们大概就了解了 RenderObject 的整个绘制流程,并且这个绘制时机我们是去“触发”的,而不是主动调用,并且更新是判断区域的。
如下图所示,所有的 RenderObject 子类都必须实现 paint 方法,并且该方法并不是给用户直接调用,需要更新绘制时,你可以通过 markNeddsPaint 方法去触发界面绘制。 ?...image.png 那么,按照“国际流程”,在经历大小和布局等位置计算之后,最终 paint 方法会被调用,该方法带有两个参数: PaintingContext 和 Offset ,它们就是完成绘制的关键所在...其实这里的问题还是在于 PaintingContext ,它有一个参数是 estimatedBounds ,而 estimatedBounds 正常是在创建时通过 child.paintBounds...到这里我们大概就了解了 RenderObject 的整个绘制流程,并且这个绘制时机我们是去“触发”的,而不是主动调用,并且更新是判断区域的。 嗯~有点 React 的味道!...同时可以看到 _SliderRender内的参数都重写了 get 、 set 方法, 在 set 时也会有 markNeedsPaint() ,或者调用 _updateLabelPainter 去间接调用
Streaming API使用的推送技术,即服务器端会主动给订阅的客户端发送通知信息,而不是客户端去调用服务器端返回消息,使用Bayeux协议和CometD用于长轮询。...这些字段有几个需要详细的描述一下: Query:Query在PushTopic的作用不言而喻,定义了哪些数据可以满足条件进行推送。Query语法和SOQL基本相同,但是有一些情况不支持。...在36.0及以前,他不包含客户端的状态,也没法跟踪已经过去的事件信息。...当新建PushTopic想要查看是否创建成功以及是否生效,或者模拟PushTopic的订阅,可以使用workbench查看相关的状态,这里以Account为例,监听Account增删改事件,有以上事件则会发送通知...当你订阅一个渠道后,你并不想接收所有的数据,比如对于客户信息,不同的人员更关注自己的客户的变化信息,这是你可以在订阅的URL后添加filter对事件通知进行过滤,推送你需要的通知信息。
切换状态的时候,colorTile的颜色并没有改变,而当我们把key去掉或者换成LocalKey类型的key,会发现每一次切换addParent状态colorTile颜色会变化。...即可以在app的任何地方更换父widget而不会丢失状态。...child, Widget? newWidget, Object? newSlot)中会根据参数操作不同,如下所示。...时,会调用build方法创建新的widget(就是在这里会执行我们的打印),updateChild时会传入我们的新widget来更新旧widget组件,widget会被更新,而复用的是比较重量的element...总结一下,上面我们主要介绍了GlobalKey的两种应用场景及原理: 可以在app的任何地方更换父widget而不会丢失状态 它可以用来从完全不同的widget树里面访问数据 下一篇文章,我们将继续探索
---- 在使用 Flutter 时,我们经常会遇到一个叫做 Key 的东西。Key 是 Flutter 中几乎所有 widget 都具有的属性。但它并不常用而容易被忽视。...说明 Key 大多数情况下对于有状态的 Widget 而言更有用,而对于无状态的 Widget 则不太需要。 何时使用 Key Key 可以放在代码的几乎任何地方而不会造成什么问题。...这些 widget 保持某些状态,并且在 widget 树中处于相同的级别。如果没有 Key,更新这样的 widget 集合可能不会产生预期的结果。...为了正确交换平铺位置,我们需要向有状态的 widget 添加 key 参数。...= null) { // 两个widget相同,位置不同更新位置,返回child。
在更复杂的应用程序中,小部件层次结构的不同部分可能对不同的问题负责; 例如,一个小部件可能呈现一个复杂的用户界面,其目标是收集特定信息(如日期或位置),而另一个小部件可能会使用该信息来更改整体呈现。...当此小部件的父级重建时,父级将创建ShoppingList的新实例,但该框架将重新使用树已存在的_ShoppingListState实例 而不是再次调用createState。...为了通知框架它改变了它的内部状态,它将这些调用包装在setState调用中。调用setState会将这个小部件标记为肮脏,并计划在下一次您的应用程序需要更新屏幕时重新构建它。...如果您在修改窗口小部件的内部状态时忘记调用setState,则框架将不知道您的窗口小部件是脏的,并且可能不会调用窗口小部件的build函数,这意味着用户界面可能不会更新以反映已更改的状态。...此外,语义上同步条目意味着保留在有状态子部件中的状态将保持附加到相同的语义条目而不是在视口中的相同数字位置上的条目。 全局Key 主要文章:GlobalKey 您可以使用全局键来唯一标识子窗口部件。
,当最后一次刷新任务结束后,会再次调用timeline函数重新设置一组更新的时间线。...一个App只能创建一个App Widget,但这并不是说我们只能有一种功能类型的组件,可以通过定义组件包,来提供多个小组件供用户进行使用,示例如下: struct WidgetExt: Widget {...} 需要注意,不同的小组件定义的kind参数要有差异。...Widget有单独的系统进程进行维护,因此即便小组件已经显示在屏幕上,其也并不是一直都是活跃的,开发者可以定义一些时机来对小组件的内容进行更新。 ...,适用于当配置项固定的场景,更多时候,可能连配置项都是动态的,比如我们的应用会根据服务端的状态来提供不同的服务,这时可提供给用户开启的服务项目就是动态的。
领取专属 10元无门槛券
手把手带您无忧上云