原创

05.深入理解State


目录介绍

  • 01.State是干什么的
  • 02.setState作用
  • 03.State实现跨帧共享
  • 04.State创建过程
  • 05.看一个案例

好消息

  • 博客笔记大汇总【16年3月到至今】,包括Java基础及深入知识点,Android技术博客,Python学习笔记等等,还包括平时开发中遇到的bug汇总,当然也在工作之余收集了大量的面试题,长期更新维护并且修正,持续完善……开源的文件是markdown格式的!同时也开源了生活博客,从12年起,积累共计N篇[近100万字,陆续搬到网上],转载请注明出处,谢谢!
  • 链接地址:https://github.com/yangchong211/YCBlogs
  • 如果觉得好,可以star一下,谢谢!当然也欢迎提出建议,万事起于忽微,量变引起质变!

01.State是干什么的

  • Flutter 宇宙中万物皆 Widget ,而 Widget 是 @immutable 即不可变的,所以每个 Widget 状态都代表了一帧。
  • 在这个基础上, StatefulWidget 的 State 帮我们实现了在 Widget 的跨帧绘制 ,也就是在每次 Widget 重绘的时候,通过 State 重新赋予 Widget 需要的绘制信息。

02.setState作用

  • setState的作用是什么
    • setState ,其实是调用了 markNeedsBuild ,markNeedsBuild 内部会标记 element 为 diry,然后在下一帧 WidgetsBinding.drawFrame 才会被绘制,这可以也看出 setState 并不是立即生效的。
  • setState源码分析
    • setState ,其实是调用了 markNeedsBuild ,markNeedsBuild 内部会标记 element 为 diry,然后在下一帧 WidgetsBinding.drawFrame 才会被绘制,这可以也看出 setState 并不是立即生效的。
      @protected
      void setState(VoidCallback fn) {
        assert(fn != null);
        assert(() {
          if (_debugLifecycleState == _StateLifecycle.defunct) {
            throw FlutterError();
          }
          if (_debugLifecycleState == _StateLifecycle.created && !mounted) {
            throw FlutterError(
            );
          }
          return true;
        }());
        final dynamic result = fn() as dynamic;
        assert(() {
          if (result is Future) {
            throw FlutterError(
            );
          }
          return true;
        }());
        _element.markNeedsBuild();
      }
    

03.State实现跨帧共享

  • 这个涉及 Flutter 中 Widget 的实现原理
    • Flutter 中的 Widget 在一般情况下,是需要通过 Element 转化为 RenderObject 去实现绘制的。
    • Element 是 BuildContext 的实现类,同时 Element 持有 RenderObject 和 Widget ,我们代码中的 Widget build(BuildContext context) {} 方法,就是被 Element 调用的。
  • Flutter构建Widget过程
    @immutable
    abstract class Widget extends DiagnosticableTree {
    
      @protected
      Element createElement();
    
    • 在 Flutter 中构建一个 Widget ,首先会创建出这个 Widget 的 Element ,而事实上 State 实现跨帧共享,就是将 State 保存在Element 中,这样 Element 每次调用 Widget build() 时,是通过 state.build(this); 得到的新 Widget ,所以写在 State 的数据就得以复用。

04.State创建过程

  • 首先看一下代码
    abstract class StatefulWidget extends Widget {
      const StatefulWidget({ Key key }) : super(key: key);
    
      StatefulElement createElement() => StatefulElement(this);
    
      State createState();
    }
    
    //看这个方法
    class StatefulElement extends ComponentElement {
      StatefulElement(StatefulWidget widget)
      : _state = widget.createState(),
        super(widget) {
    
    
      @override
      void update(StatefulWidget newWidget) {
        super.update(newWidget);
        assert(widget == newWidget);
        final StatefulWidget oldWidget = _state._widget;
        _dirty = true;
        _state._widget = widget;
    
        rebuild();
      }
    
  • StatefulWidget 的 createState 是在 StatefulElement 的构建方法里创建的, 这就保证了只要 Element 不被重新创建,State 就一直被复用。
  • 看 update 方法,当新的 StatefulWidget 被创建用于更新 UI 时,新的 widget 就会被重新赋予到 _state 中。

05.看一个案例

  • 代码如下所示
    class TestState extends StatefulWidget{
      @override
      State<StatefulWidget> createState() {
        return new TestPageState();
      }
    }
    
    class TestPageState extends State<TestState>{
    
      String data = "逗比";
    
      @override
      Widget build(BuildContext context) {
        return new Scaffold(
          appBar: new AppBar(
            title: new Text('测试的案例代码'),
          ),
          body: new Center(
            //第一处
            child: new Page(data),
          ),
          floatingActionButton: new FloatingActionButton(
            onPressed: (){
              setState(() {
                //第四处
                data = "杨充";
              });
            },
          ),
        );
      }
    }
    
    class Page extends StatefulWidget{
    
      String data;
    
      Page(String data) {
        //第二处
        this.data = data;
      }
    
      @override
      State<StatefulWidget> createState() {
        return new PageState();
      }
    
    }
    
    class PageState extends State<Page>{
    
      @override
      Widget build(BuildContext context) {
        return new Scaffold(
          body: new Center(
            //第三处
            //child: new Text(widget.data),
            //下面这种是错误的
            child: new Text(data),
          ),
        );
      }
    }
    
  • 操作步骤
    • 当我们点击 4 中的 setState 时,却发现 3 中 Text 没有发现改变, 这是为什么呢?
  • 原理分析
    • 问题就在于前面 StatefulElement 的构建方法和 update 方法。
    • State 只在 StatefulElement 的构建方法中创建,当我们调用 setState 触发 update 时,只是执行了 _state.widget = newWidget,而我们通过 _DemoPageState(this.data) 传入的 data ,在传入后执行setState 时并没有改变。
    • 如果我们采用上图代码中 3 注释的 widget.data 方法,因为 _state.widget = newWidget 时,State 中的 Widget 已经被更新了,Text 自然就被更新。

参考博客

  • https://juejin.im/post/5d0634c7f265da1b91639232

其他介绍

01.关于博客汇总链接

02.关于我的博客

  • github:https://github.com/yangchong211
  • 知乎:https://www.zhihu.com/people/yczbj/activities
  • 简书:http://www.jianshu.com/u/b7b2c6ed9284
  • csdn:http://my.csdn.net/m0_37700275
  • 喜马拉雅听书:http://www.ximalaya.com/zhubo/71989305/
  • 开源中国:https://my.oschina.net/zbj1618/blog
  • 泡在网上的日子:http://www.jcodecraeer.com/member/content_list.php?channelid=1
  • 邮箱:yangchong211@163.com
  • 阿里云博客:https://yq.aliyun.com/users/article?spm=5176.100- 239.headeruserinfo.3.dT4bcV
  • segmentfault头条:https://segmentfault.com/u/xiangjianyu/articles
  • 掘金:https://juejin.im/user/5939433efe88c2006afa0c6e

评论

留言