Flutter路由栈和生命周期解析

作者: zhx喜籽 | 来源:发表于2020-02-12 11:21 被阅读0次

    什么是路由

    路由(Routes)是什么?路由是屏幕或应用程序页面的抽象。
    Flutter 使我们能够优雅地管理路由主要依赖的是 Navigator(导航器)类。这是一个用于管理一组具有某种进出规则的页面的 Widget,也就是说用它我们能够实现各个页面间有规律的切换。而这里的规则便是在其内部维护的一个“ 路由栈”。
    命名路由

    在一般应用中,我们用的最多的还是命名路由,它是将应用中需要访问的每个页面命名为不重复的字符串,我们便可以通过这个字符串来将该页面实例推进路由。
    例如:

    new MaterialApp(
      home: new Screen1(),
      routes: <String, WidgetBuilder> {
        '/screen1': (BuildContext context) => new Screen1(),
        '/screen2' : (BuildContext context) => new Screen2(),
        '/screen3' : (BuildContext context) => new Screen3(),
        '/screen4' : (BuildContext context) => new Screen4()
      },
    )
    

    路由栈

    Navigator维护了一个堆栈,来保存路由跳转的状态。
    screen1跳转到screen2

     Navigator.pushNamed(context, '/screen2') 
    
    image

    退出路由pop
    Navigator.pop()

    image

    切勿用pushNamed替代pop,不然就会出现下面的情况了。

    image

    生命周期

    简单地聊完路由栈,接下来介绍 StatefulWidget一系列的生命周期。

    image

    上图就是 State 的生命周期图。

    StatefulWidget.createState()

    Framework 通过调用 StatefulWidget.createState() 来创建一个 State。

    initState()
    新创建的 State 会和一个 BuildContext 产生关联,此时认为 State 已经被安装好了,initState() 函数将会被调用。通常,我们可以重写这个函数,进行初始化操作

    didChangeDependencies()
    在 initState() 调用结束后,这个函数会被调用。事实上,当 State 对象的依赖关系发生变化时,这个函数总会被 Framework 调用。

    build()
    经过以上步骤,系统认为一个 State 已经准备好了,就会调用 build() 来构建视图。我们需要在这个函数中,返回一个 Widget。

    deactivate()
    当 State 被暂时从视图树中移除时,会调用这个函数。页面切换时,也会调用它,因为此时 State 在视图树中的位置发生了变化,需要先暂时移除后添加。⚠️注意,重写的时候必须要调用 super.deactivate()。

    dispose()
    当 State 被永久的从视图树中移除,Framework 会调用该函数。在销毁前触发,我们可以在这里进行最终的资源释放。在调用这个函数之前,总会先调用 deactivate()。⚠️注意,重写的时候必须要调用 super.dispose()

    didUpdateWidget(covariant T oldWidget)
    当 widget 的配置发生变化时,会调用这个函数。比如,Hot-reload 的时候就会调用这个函数。这个函数调用后,会调用 build()。

    setState()
    当我需要更新 State 的视图时,需要手动调用这个函数,它会触发 build()
    一般情况下我们用的最多的是initState,build,deactivate,dispose,setState。接下来也主要讲initState以及dispose在路由跳转过程中的触发条件。

    路由跳转时的initState,deactivate,dispose
    一开始我们是这么写的

    @override
    void initState() {
        super.initState();
        print('------initstate--------');
    }
    
    void deactivate() {
        super.deactivate();
        print('-----deactivate----');
    }
    
    void dispose() {
        super.dispose();
        print('----dispose--------');
    }
    

    当我们通过pushNamed跳转到其他路由,发现deactivate触发了,但是dispose并没有触发,并且再次通过pushNamed回到本页的时候,initstate也并没有再次执行。
    写多了Vue单页面应用的同学,应该知道这其实很让人困扰。我们很多时候需要像Vue一样,在created的时候初始化数据,在beforeDestroy的时候移除页面一些监听事件或者销毁定时器,防止内存泄露。

    让我们回到生命周期说明那里:

    deactivate() 当 State 被暂时从视图树中移除时,会调用这个函数。
    dispose()当 State 被永久的从视图树中移除,Framework 会调用该函数。

    此时是不是恍然大悟!pushNamed只是暂时把视图移除了,并没有彻底移除,所以导致了一些奇怪的问题(前提是你跟我一样,业务上需要控制页面的初始化和销毁)

    那怎么办。此时popAndPushNamed闪亮登场!用它替代pushNamed,你就会发现该触发的事件都触发了~

    popAndPushNamed将当前路由弹出并跳转到新的路由,彻底移除旧路由。
    还有类似的方法pushReplacementNamed,pushNamedAndRemoveUntil等,就不赘述了。
    取消导航Header的返回键

     AppBar(automaticallyImplyLeading: false)
    

    WillPopScope取消Android物理返回键
    这个方法也可以取消iOS默认左右滑动切换路由。

     Widget build(BuildContext context) {
        return WillPopScope(
            onWillPop: () async {
              return false;
            },
            child: Scaffold(
                // Your Code
            )
        );
    }
    
    

    作者:Harry_Chen

    链接:https://juejin.im/post/5df74f7cf265da33d645b307

    来源:掘金

    相关文章

      网友评论

        本文标题:Flutter路由栈和生命周期解析

        本文链接:https://www.haomeiwen.com/subject/frbqfhtx.html