Navigator2.0到底是怎么回事,它是如何支持deepLikn的?

命名路由与动态路由

Flutter中的路由分为命名路由和动态路由两种
  • 动态路由 我们一般会这样写
Navigator.push( context,
           MaterialPageRoute(builder: (context) {
              return DetailPage();
           }));
          },
         )
复制代码
  • 命名路由
  1. 注册路由表
 routes:{
  	"detail_page":(context) => DetailPage(),
   	"/":(context) => MyHomePage(title: 'app首页')
        } 
复制代码
  1. 路由跳转
 Navigator.pushNamed(context, "detail_page",{Object arguments})
复制代码

这两种路由的的特点

  • 动态路由:分散式管理 每次进行路由跳转操作的时候都要导入目标路由的头文件
    优势:依赖编译器,当目标路由名字或者参数有改动的情况下,编译器可以直接检测出错误。
  • 命名路由:集中式管理 路由跳转的时候只需要传入路由表中的注册的key值就可以
    优势: 跳转不需要导入头文件,可以通过硬编码的方式进行跳转,语义更加明确

以我个人经验来看,开发中更推荐的方式还是使用命名路由。当然没有是绝对正确或者错误的,清楚了两者的优劣之后,结合自己当前的业务 才能做出明智的选择。
这两种路由在使用上有很大的区别,那么在实现原理上有什么区别么?为了描述清楚这个问题 我画了一张图,如下。

20210508161510.jpg

从上图可以看出在实现上 其实命名路由就行根据传入的 name 找到对应的router 然后调用了动态路由的方法,所以没有啥本质区别,这样设计的好处就是,动态路由和命名路由是互相兼容的,这种编程方式值得借鉴学习。

Navigator 1.0存在的问题

上面那张图有一个 _history的数组,这数组可能有人会称之为路由栈,但是这里要强调下我们平时所说的路由栈,其数据结构使用的数组(array),而不是栈(stack)。
但是这个_history是私有的 不允许外部类进行操作,如果你想操作_history 只能通过系统提供的 push pop pushReplacement 等方法。所以1.0存在的问题就是 不能够灵活的操作这个 _history。假设我们有这样的一个业务

通过一个网页唤起我们的app 然后一次进入 ScreenA -> ScreenB -> ScreenC 最终停留在ScreenC,但是我希望用户是直接看到ScreenC 并不是看到从ScreenA到 ScreenC的转场,基于这种业务情况也许Navigation 1.0也可以实现,就是通过push操作 然后禁掉转场动画,似乎也可以实现,但是如果可以直接操作_history似乎会更优雅一点,比如我们可以用如下方式进行跳转

Navigator.pushNamed(context, "/ScreenA/ScreenB/ScreenC")
复制代码

如果我还想传入参数怎么办呢 ,我们可以这样写

Navigator.pushNamed(context, "/ScreenA/ScreenB/ScreenC?name=zhansan&age=12")
复制代码

咦?好熟悉的感觉 这看起来就很像web端的链接了。
不过这在1.0的时候可不太好实现,于是Flutter推出了Navigator2.0

Navigator 2.0是如何满足更复杂的业务情况

那么在Navigator 2.0里面,Flutter是如何解决这个问题的呢?可能最简单的方式就是把 _history 从私有的变成公有的。但是这样话 _history 又会变的很危险,我认为这对上线的应用可能会有很大的潜在风险
所以在Navigator 2.0里面Flutter用一种更委婉的方式解决这个问题,为了展示这个过程我画了下面的这张图

20210508181617.jpg
也就是说 Navigator传入了一个叫做pages的列表,然后将pages数组中的元素通过_history.addAll()方法转化为_history,那么开发者就可以通过操作pages这个数组从而达到操作_history的目的,这样的设计还有一个好处就是 Navigator 2.0完全兼容 Navigator 1.0,因为究其原理,最终我们通过 push pop 等,其实都是在操作 _history 者数组,这与1.0的设计完全吻合

那么既然我们可以自由的操作pages 那么关于上面那个业务场景我们就可以这样实现
pages.add(ScreenA)
pages.add(ScreenB)
pages.add(ScreenC)

这样在ScreenA ScreenB ScreenC 就可以不通过 push 这个方法 添加到了 _history 中了。
原理解释清楚了,剩下的就是编写代码了,至于Navigator 2.0 中设计到的API 以及如何使用可以前往github.com/coder-dongj…
下载代码自行查看

最后: 这世界上最遥远的距离就是知道和做到

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享