带你深入理解不一样的 Flutter( 二 )
可以看到 StatefulWidget 本身依旧是不可变的 , 所以 title 属性需要定义为 final, 但是 build 方法被放到了 State 中 ,count 也被移动到 State 中 , 所以 count 可以支持跨帧保存 。
为什么写到 State 就可以实现跨帧保存 ? State 和 Widget 是什么关系?这就需要介绍 Flutter 中另一个概念: Element。
事实上如果查看 Flutter 对于 Widget 的定义 , 可以看到官方对于 Widget 的定义是 Describes the configuration for an [Element]., 也就是 Element 才是 Widget 真正的体现 。
文章插图
对于 Element 大家可能会比较陌生 , 因为 Flutter 开发中很少直接使用 Element。 但是如果说到 BuildContext 相信大家就不会陌生 , 因为 BuildContext 在开发中经常被使用到 , 而 Element 恰好就是 BuildContext 的实现类 , 你使用的 BuildContext 其实就是 Element。
所以在 Flutter 的开发过程中 ,Element 其实扮演着十分重要的角色:一个 Widget 被首次加载时 , 会先创建出它对应的 Element, 就比如上面介绍的 StatefulWidget, 会对应先创建出 StatefulElement ;而 StatefulElement 被调用的时候 , 会先通过 widget.createState() 创建出 State, 之后 _state 就被保存在 Element, 所以 _state 可以跨 Widget 保存 。
文章插图
理解了吗? Element 才是一个真正的工作节点 , 而 Widget 仅仅是一个“配置信息”。
因为 Widget 仅仅是“配置信息”, 所以它可以每次改变时都被重构 , 而 Element 才是真正的节点 , 它每次读取 Widget 的状态去配置和绘制 , 但是 Element 并不是每次都重新创建 , 而是在 Widget 首次被加载时通过 createElement 创建出来 。
什么是首次加载呢?通俗点来说就是这个 Element 在 mount 的时候 。 举一个例子 , 如下面代码所示:
- DemoPage Scaffold body StatePage
- StatePage data “init” _StatePageState data
- floatingActionButton setState _DemoPageState内 data “Change By setState”
- 但是最终结果 StatePage 界面依然显示 “init”。
class DemoPage extends StatefulWidget {@override_DemoPageState createState() => _DemoPageState();}class _DemoPageState extends State {String data = "http://kandian.youth.cn/index/init";@overrideWidget build(BuildContext context) {return Scaffold(/// 将data数据传递给StatePagebody: StatePage(data),floatingActionButton: FloatingActionButton(onPressed: (){/// 改变data数据setState(() {data = "http://kandian.youth.cn/index/Change By setState";});},),);}}class StatePage extends StatefulWidget {final String data;StatePage(this.data);@override_StatePageState createState() => _StatePageState(data);}class _StatePageState extends State {String data;//// data是从StatePageState的构造方法传入_StatePageState(this.data);@overrideWidget build(BuildContext context) {return Container(child: new Center(child: new Text(data ?? "")),);}}
为什么 StatePage 界面依然显示 “init” ?因为虽然 StatePage 这个 Widget 的 data 发生了改变 , 但是 StatePage 的 createState() 方法只在第一次被加载时调用 , 对应创建出来的 state 被保存在 Element 中 , 所以 _StatePageState 中的 data 只在第一次时被传递进来 。关键就在于 _StatePageState 创建时 data 只被赋数一次 。
如果这时候要让 StatePage 的 data 正常改变 , 就需要使用 widget.data。 看出来了没 ,如果把 State 放到 Element 的级别上来看 , 通过 widget.data 去更新的逻辑 , 是不是 Widget 看起来就很像是一个配置文件。
那最后再问一个问题: Widget 和 Element 的对应关系是怎么样?
四、Element 和 Widget 的对应关系从官方的注释里可以看出 ,Widget 做为配置文件 , 和 Element 是应该是一对多的关系 , 因为真实工作的其实是 Element 树 , 而 Widget 作为配置文件 , 可能会在多个地方被复用 。
文章插图
举个例子 , 如下代码所示 , 通过运行后可以看到 textUseAll 在多个地方被 inflated 并且正常渲染出 3333333 的效果 。
这是因为 textUseAll 仅仅是作为配置文件 , 所以被多个 Element 加载并不会出现问题 , 因为这并不是一个真正的 "View" 被多个地方加载 。
final textUseAll = new Text("3333333",style: new TextStyle(fontSize: 18, color: Colors.red),);class MyHomePage extends StatelessWidget {void goNext(context) {Navigator.of(context).push(MaterialPageRoute(builder: (context) {return ShowPage();}));}@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(),body: Center(child: Container(color: Colors.blue,height: 80,child: Stack(children:
- S7|vivo S7的6400万有多强?带你感受“神奇动物在哪里”
- 启动|拼多多深入布局母婴产业带 补贴+直播启动“母婴产品溯源”行动
- 工地|“智慧工地”是什么?记者带你全方位了解
- RFID在冷链物流中的作用-RFID冷链资产管理解决方案
- 《深入理解Java虚拟机》:对象创建、布局和访问全过程
- 现场|逛展看未来丨展会现场还能这么玩?带你解锁萌娃的逛展“姿势”
- 应用出海不太难!12月8日HMS出海生态联盟峰会带你加速“航海”
- 都说编程要逻辑好,如何理解这个逻辑
- 成长思维:我大哥对“道法术器”的理解,80%的人不懂
- Linux信号透彻分析理解与各种实例讲解