![带你重新“玩转”Flutter](https://static001.infoq.cn/resource/image/ed/3f/edb63816fbf02fc9c8de86ddb7d1053f.jpg)
Flutter 作为一项已经逐渐进入规模化实践的技术,它的价值已经初步获得认可,后续应该有不错的生命力。作为较早期的 Flutter 实践者,我一直在思考 Flutter 的技术价值以及如何释放这些价值,本篇尝试从一个新的视角去结构化的梳理 Flutter 的技术价值并做对应的应用分析。
这里不会涉及到 Flutter 具体领域的技术点,但是会结合我们团队过去的探索实践,在技术使用策略的层面做一些总结,希望能帮助到小伙伴们在开发实践中思考提炼,抬头看路,仰望星空,找到未来的创新方向。
前端有些啥问题
要溯源 Flutter, 就得从前端说起了。这里的前端是相对于后端的概念,大概泛指通过图形界面实现用户交互的终端技术。这个领域一直很有活力,伴随着互联网一路走来,很多新思路和新技术都有点眼花缭乱:上古的 MVC 已经不大提起了,老一辈的 MVP,MVVM 也逐渐暗淡,新一辈的 Vue,Angular,React 方兴未艾,还有 Redux, Mobx, Hooks 推波助澜。这些技术都像是一个个有感情的小生命,有的热情,有的文艺,有的高冷,十分热闹。也许你会想:它们都在说个啥?它们都想解决一个啥问题?
节点,连接和网络
互联网是这一切存在的大背景,互联网有 3 个大要素:节点,连接和网络拓扑结构。每一个要素的进化都会给前端带来升级和变革:从 PC 互联网到移动互联网再到物联网是节点在进化;充满想象的 5G 时代是连接在进化;从中心化到分布式是网络拓扑结构在进化。前端的使命是让用户(人)高效的嵌入到网络之中,让人和设备融合为一个有生命的网络“节点”。
![](https://static001.geekbang.org/infoq/dc/dc8989275163c9aa35ce597abc5b4e98.png)
PS:网络模型可以适配到前端的很多场景,里面的“节点”可以代指手机设备,应用程序,进程,页面,甚至组件。
节点与前端技术
前端技术是用户(人)与设备的粘合剂,让二者有机的构成一个网络节点。我尝试剖析下前端技术在节点中的形态:首先它需要提供界面给用户,并响应用户的交互;需要管理和远端节点的通信,交换信息;还需要管理当前节点的信息状态;最后,为了方便的嵌入到网络中,节点需要一个友好的“外观”,就是生命周期。生命周期描述了节点的诞生,消亡,所拥有的权益,和所承担的责任。
![](https://static001.geekbang.org/infoq/28/28a14ae2ce2c34d2200614afe272d9dd.png)
PS:这个分治模型也具有一定的通用性,可以适用在应用程序,页面,或者组件。
前端要解决的问题
当然,前端技术作为一种软件技术,在日常的工程开发中也需要基础的构建部署支撑。那么,综合前面的讨论,前端要解决的基础要素问题有:
•远端通信
•界面管理
•生命周期
•状态管理
•构建部署
这里面生命周期管理是一个比较“隐形”的问题,它其实就是构建“外观”描述,也就是“组件化”。这些基础要素问题的结构关系大概是:
![](https://static001.geekbang.org/infoq/21/21f0aff1f92d8e566e6ded1ce507a7a1.png)
这几个基础要素问题的解决往往不能孤立的进行,在设计解决方案的时候需要彼此配合。前端领域的技术方案通常都会合并解决其中的几个问题,比如:React 解决界面管理和生命周期;Vue 解决了界面管理,状态管理,和生命周期;Redux 专注解决状态管理;GraphQL,BFF,Serverless 解决远端通信;webpack 解决构建部署等等...
那么,Flutter 解决了什么问题?或者,Flutter 可以解决哪些问题呢?
Flutter 都有些啥
有趣的技术方案应该有自己旗帜鲜明的个性,做架构设计往往是遇到了独特的问题或者发现了更好的工具。因此,使用 Flutter 做解决方案的时候,应该梳理下 Flutter 都带来了些什么。一般来说,主要有 Dart 语言,Dart 运行时(VM),GUI 框架,和相关的开发构建工具。
Dart 语言
Dart 语言不好说有多优秀,总的来说是一门工程“友好”的现代语言。也许感觉平淡无奇,但官方在介绍 Flutter 的时候,还略有“骄傲”的展示了它的包容性:它能较为原生的支持声明式,过程式,面向对象,函数式,和响应式等业务场景,它给技术方案实现提供了很自由的范式空间,这是值得发掘和尝试的。结合我自己的实践,有几个点值得一说:
•支持类似“协程”处理(async/await/yield):Dart 是单线程的,但是支持异步。这一点需要在使用中去体会,不展开说,理解深了以后,可能对很多问题都有新解法。
•提供 Stream:当你要进阶学习 Flutter 的时候,很多地方能见到它。它能做流式数据处理,函数组合,传输控制,属于进阶必知必会。
•mixin 特性:这是很有用的特性,尤其在架构设计方面。它提供了新的组合方式,在做功能组合的时候,Dart 可以使用对象注入,或者高阶函数,或者 mixin。
Dart-Runtime / VM
当你引入 Flutter,你就有一个 Dart-Runtime 啦。当然,它本来的意义是支持 Flutter 运行的,然而就像 JS 的 V8 引擎一样,本来是用来支持 H5 页面的,后面的脑洞就越开越大了。当然 Dart 没有 JS 的动态能力(特殊的场合也可以),但它是跨端的,而且 aot 性能有保障,发掘空间较大,还能同时覆盖几乎所有场景,手机 app 开发,PC 的构建部署,服务端,甚至 serverless 运行时。
Flutter 应用开发框架
Flutter 带来了高性能的跨平台 GUI Framework,这没啥可说的,用就是了!但如果已经有了自己的开发生态,舍弃成本太大,又想“借用”下 Flutter 的技术优势,大概有几种方案:
•语言转换,基本上就是把其他语言的布局结果交给 Flutter Framework。
•中层 Framework 介入,选择一棵树介入,这样对接面会小一些。
•底层 Framework 替换,整个替换掉 Flutter Framework, 直接使用底层的 Engine。
![](https://static001.geekbang.org/infoq/b5/b5203485b6c618f3799a268b305addcb.png)
当然,还有一种方式就是混合开发了,需要实现混合栈管理,而且在 1.22 版本以后,Flutter 升级了 Navigator 组件,提供了 Navigator 2.0,这对混合开发是一个利好。
开发构建工具
值得一提的是 HotReload,谁用谁知道。热部署不仅界面开发需要,这是个通用需求,如果在服务端通过 Dart 实现一个,也是极好的。
Flutter 的构建工具并无太多亮点,而且因为 Dart 语言在 Flutter 中不支持反射(产物太大,增加包体积),业务架构实现上很多需要依赖于编译时处理的技术,这对构建系统的能力有较大依赖的。换一个角度,因为这一领域尚没有成熟方案,加上 Dart 的工程“友好”,可能实现由一种语言来统一前端开发,后端开发,以及构建和部署,真做到了会很酷!
Flutter 可以有些啥玩法
讨论前端要解决的几个基础要素问题,也讨论了 Flutter 带来的技术工具,结合这两点,看看利用 Flutter 都能做些啥。
远端通信
“远端通信”是一个做了抽象的概念,具体形式会根据“节点”的定义不同而不同。可以是指物理设备之间的通信(手机与服务器),也可以指模块之间(页面与另一个页面)的通信,还可以指组件之间(两个 StatefulWidget 之间)的通信。因为在 Flutter 中“一切皆是 Widget”,所以简化的看,Flutter 里面大概分为两种情形:面向服务器的通信和组件(Widget)之间的通信。
•面向服务器的通信:这方面有传统的 Restful,GraphQL,还有兴起于“云原生”概念的 Serverless。借助于 Dart 的能力延伸,Dart-Runtime 可以成为 Serverless 的可选容器,那么前后两端都可以使用 Dart 来开发,如果再用 Dart 补足中间的构建部署 pipeline,那么可以搭建出一个很“云原生”概念的应用程序开发流(dev flow):
![](https://static001.geekbang.org/infoq/78/78a59c420d793193e95d2ffdb6ec79eb.png)
Flutter 的跨端能力结合云原生的弹性部署,前后端的实现可以放到一起,它们之间的调用也变得简单自然,有理由相信这会是一个高效的开发方式。闲鱼已经做了前期的探索,并在业务中尝试落地。
此外,GraphQL 与 Flutter 也是值得尝试的组合,GraphQL 和 React 范式在理念上很对味口,但是我们并没有尝试过。
•组件之间的通信:Flutter 提供的基础业务编程组件是 StatefulWidget 和 StatelessWidget,它们是按树形结构来组织的,并提供了 InheritedWidget 来支持它们之间的通信,在通信方式可以总结出 3 种:
Notify 型:通知/监听模式,Flutter 提供了 ValueNotifier 和 ChangeNotifier, 简单方便,适用于轻量信息通信,参见 Provider
Invoke 型:接口调用模式,类似轻量 RPC 方式,在 Flutter 的应用架构设计中竟然很少见到。它确实有些重,但是有前面的模式没有的优势:它是双向的。
Transmission 型:数据传输模式,Dart 提供了 Stream 来支持这种模式。使用灵活,扩展方便,几乎是框架设计必备,参见 BLoC。
![](https://static001.geekbang.org/infoq/81/811af17dcfcdd88d909afa6e0964e132.png)
状态管理
状态管理是个大问题,它由两个元素构成:状态和处理状态的逻辑。在代码实现上,状态就是数据,逻辑就是函数。当它们变得复杂的时候,解决的办法其实就是拆分,然后再合理的组合。我尝试从状态和逻辑的拆分选择上来列举所有可能的解法:
•状态不拆,拆分逻辑: 这种做法的特点全局共用一个状态结构体对象,所有状态全部放在这个对象中,叫做“统一状态管理”。只有一个数据对象,就消除了各个处理逻辑之间信息共享问题,逻辑内部没有状态,变得非常的纯粹(比如纯函数来实现),再将逻辑以合适的方式组合成一个整体,实现上界限清晰,简单优雅,代表的方案就是 Redux。
如果采用这种设计方案,推荐使用函数式风格来实现,这倒不是因为函数式“更高效”,“更优雅”之类的,而是它与函数式的思路十分的契合,在实现上更容易把握住思路。用面向对象来实现也并没有问题,最后的效果取决于你所面临的工程环境和用户。
这种状态管理好处显而易见:一处状态发生改变,不需要到处发事件同步。但是如果用在复杂大业务上面(比如一个有数十个页面流程的业务产品),状态必定是复杂的,状态结构体必然是庞大的。Redux 的方式很好的管理了逻辑,如果要管理一个统一庞大的状态数据,也许内存级别的 SQL 是个不错的主意,GraphQL-Client 给了我们启发,我们也正在尝试实践。
![](https://static001.geekbang.org/infoq/c9/c9c66de8d7f961fb6484f7f81bd0387b.png)
•逻辑不拆,拆分状态: 我把这种叫做“步进状态管理”,实际上这类似于状态机模式。但如果要真正使用,状态必须是有限的,而且不能经常变动。这与互联网持续多变的业务需求实际是不符合的,所以采用这种方式的设计几乎没有。但在一些很严肃的业务场景中,比如交易流程,一旦定下来就不容易变动。这时,步进状态管理就很合适了。
![](https://static001.geekbang.org/infoq/2c/2c8af3bfc6cf3399db804da35a87959b.png)
•同时拆分逻辑和状态: 这是容易想到方案,在更细的粒度上,将状态和它对应的处理逻辑拆分打包,变成更小的域(scope),然后统一协调这些子域(subModel),我把这种叫做“组合状态管理”。进一步的方案可以统一定义 subModel 的基础行为,然后引入调度器来协调管理它们,subModel 之间还可以共享上下文来共享信息等等。
这种思路形式自由,可以采用的实现方式很多,经典的面向对象当然不在话下,scoped_model 采用的就是这种思路,scoped_model 实现的简单易懂,同时能力也比较有限。当然也可以采用函数式的方式,高阶函数+闭包也能很好的实现,但是圈内没有看到有相关的设计实现。还有一点,Dart 提供了 Mixin 特性,通过这个特性,可以得到更简洁的实现方案。比如,可以沉淀很多特定的 Model,然后通过 with 选择组合到业务 Model 中来(参考 Flutter Framework 中 WidgetsBinding 的实现)。目前 flutter-hook 在做这方面的探索,flutter-hook 看起来有些迷惑,其核心就是利用了 Dart 的 Mixin 特性来组合状态。
![](https://static001.geekbang.org/infoq/18/18cf94510c1cfa8efba36d49e9fc5ba6.png)
界面管理
Flutter 使用了响应式 UI,目的就是让业务开发减少界面的管理工作,只要提供好页面“描述”就行了。虽然 Flutter 内建了类似 Virtual Dom 的 Diff 机制,但是,做这个 Diff 也是要费性能的,如果我们在框架设计上能内建的把 Diff 工作提前到数据层,是不是可以提升性能呢?
![](https://static001.geekbang.org/infoq/e6/e62e14f168091fac8d857cbef26e832d.png)
我们尝试了几种方法,受制于在 Flutter 中 Dart 不能反射,效果不理想,也许后续生态完善之后会有好的解法。
在 UI 开发中,Flutter 一直有一个隐隐的声音就是动态化,官方好像是“忽略”的,这里也不谈了。
生命周期
Flutter 通过 StatefulWidget 给业务开发提供了基础的生命周期管理。组件生命周期的设计是随着业务场景的不同而不同的,我自己的理解,设计生命周期要从两点出发:一是组件从诞生到消亡的时间线,二是组件在场景中所拥有的权益和所承担的责任。生命周期的扩展原点是 StatefulWidget,因业务场景不同而扩展不同,很难展开讲。
举个例子,如果使用原生 Flutter 开发(或者叫纯 Flutter 开发),StatefulWidget 所提供的生命周期是足够的。但是如果要做混合开发,引入混合栈后,显然就不够用了。这时候就需要提供新的组件来扩展生命周期,更好的满足混合场景的开发。当时我在做混合栈的时候并没有能理解到这一点。
结语
本篇从分析前端开发需要面对的几个基础核心问题入手,结合 Flutter 带来的技术工具,尝试结构化的分析 Flutter 在业务开发中可能的技术选择和探索方向。当然,技术同学既要仰望星空,还需要脚下看路,对于 Flutter 开发中的热点技术问题,欢迎关注闲鱼技术公众号的其他文章,或者加入我们,和闲鱼一起做一点不一样的技术!
本文转载自:闲鱼技术(ID:XYtech_Alibaba)
原文链接:带你重新“玩转”Flutter
评论 1 条评论