3.1 flutter
Flutter是由Google开发的跨平台框架,目前支持Android、iOS、Windows、macOS、linux、web几个平台。而根据平台适应性,可以分成两个部分的代码
- 平台无关型代码
- 平台相关型代码
平台无关型代码主要包括通用的界面以及业务逻辑。而平台相关型代码主要包括嵌入式驱动、持久层以及不同平台的响应式界面。
而平台相关型的代码主要遵循抽象的原则,即将部分一致性的代码使用接口封装,并在各个平台调用具体的实现来进行。
模块化
在实际的项目中,我们需要重点关注业务点,尽量将一个单独的业务点构建成一个模块,不同模块之间使用框架进行通信,并注重不同模块之间的解耦。
一般的应用可以分成共享模块与业务模块两大类别。业务模块依赖共享模块来使用公用的功能,例如存储等。而具体的业务模块之间也可能存在依赖的关系,我们需要在每个业务模块中定义需要供其他模块使用的接口,并供其他的业务模块使用。
同时,业务模块应当遵循可插拔的原则,即可以随时的进行替换,这需要用到动态调用的技术,即不同模块之间使用协议进行通信,而不需要进行相互依赖。
这一部分仍在探索中,等待后续在实际项目的开发中继续完善和迭代。
插件化
插件化与组件化不同,其提供的是整个应用的扩展能力,插件分为宿主、协议和插件内容三个部分,在实际的项目中,一般使用插件来提供额外的功能,比如新的界面和业务、数据的后处理等。
我们需要根据实际的项目来定义插件的扩展,输入和输出,界面等。
目前插件化在Flutter项目中的应用较少,我们可以参考Android项目的插件化开发。
项目结构
大致的项目结构如下,实际的项目结构会根据项目做出具体的调整或者修改。
Project
└─ android
└─ lib
└─ bean
└─ config
└─ dao
└─ entity
└─ model
└─ io
└─ network
└─ database
└─ file
└─ ui
└─ page
└─ component
└─ widget
└─ util
└─ viewmodel
└─ main.dart
└─ linux
└─ macos
└─ moduleA
└─ moduleB
└─ web
└─ windows
└─ .gitignore
└─ .metadata
└─ analysis_options.yaml
└─ pubspec.lock
└─ pubspec.yaml
└─ README.md
项目的分层
项目的分层是实现关注点分离的常用手段,通常我们使用分层来实现不同业务的解耦:例如视图和逻辑的解耦。
在实际项目中,我们可以将一个项目分层五层:视图层(UI)、视图模型层(ViewModel)、业务层(Model)、仓储层(Repo)、持久层(Database、File、Network etc)
视图层
视图层在Flutter项目中指的是UI界面,视图层应当仅关注界面相关的逻辑,并使用视图模型层的数据呈现界面。
注意:视图层只能使用内部数据或者视图模型层提供的数据。
视图层不应当包含除了界面显示依赖的任何业务逻辑,除了使用判断表达式来区分需要显示的内容等。也不应该在视图层中直接修改界面,而应当向视图模型层/模型层提交Intent事件来修改页面数据。
视图层使用单向数据流进行渲染,也就是说,界面不能直接修改任何外部数据,而是要通过Intent事件接口的方式交给其他层处理,并进行视图的更新。
例外:当视图中包含动画、内部数据时,可以直接在空间的内部进行变更。
视图模型层
视图模型层用于向界面提供直接的数据,其数据来源主要有:
- 视图模型层内部定义的与视图直接关联的数据。(仅供界面独有)
- 模型层定义的与业务相关的运行时数据。(业务相关)
- 仓储层定义的持久化数据。
需要注意的是,无论数据的来源在哪,同一概念的数据应当具有单一的来源,从而避免数据来源的不一致性。
模型层
模型层设计单独的业务逻辑,提供数据处理,具体的业务逻辑相关的功能。模型层可以提供业务相关的运行时数据,模型层主要的功能有:
- 向视图模型层、视图提供数据来源。
- 存储与业务相关的运行时数据。
- 接收来自视图模型层的事件,并进行数据处理。
- 将数据的修改提交至仓储层。
仓储层
仓储层是持久化的入口点,所有运行时数据与外部数据交互的逻辑均在仓储层中实现,仓储层可以从多个来源获取数据,也可以向多个来源提交数据。仓储层可以对接的数据来源包括:
- 本地数据库,在实际项目中,一般指sqlite数据库。
- 网络接口,从网络中获取必要的数据等。
- 文件,一般仓储层可以将数据放入到文件中。
- 嵌入式设备接口,也需要从仓储层写入或者读取数据。
仓储层的设计不关心其距离的数据来源,向上层提供统一的持久层数据接口,从而提升代码的可维护性
相关概念
推荐:使用流数据来获取界面的状态
流数据,即Stream<T>,可以自动的获取最新的数据和状态,而不需要进行手动的修改,因此,推荐使用流数据来渲染界面,以及处理数据。
流数据是自动的,不需要进行手动提交,因此,其能极大程度上避免数据不一致的情况发生。
流数据的概念和RectiveX框架比较类似,可以对比着进行学习和使用。
框架
在本部分介绍考虑的框架并说明选择该框架的理由
状态管理
计划采用BLoC作为状态管理的框架。
对于比较大型的项目来说,使用统一的状态管理框架是十分有必要的,目前Flutter状态管理的框架可以参考的有:
- Provider
- Riverpod
- setState
- InheritedWidget & Inherited Model
- Redux
- Fish-Redux
- BLoC/Rx
目前,打算使用BLoC作为状态管理的主要框架,主要考虑到其具有完整的设计逻辑、而且可以很好的结合流数据的处理逻辑,比较适合用该框架做大型项目的开发。
而且BLoC也是目前更新频率较高,而且一致在维护和更新的框架。
具体的使用方式可以参考flutter_bloc使用解析 - 掘金。
pub地址:flutter_bloc | Flutter Package (pub.dev) 当前版本 8.1.2 5339Likes
github地址:felangel/bloc
序列化
Json序列化目前主流的有json_serializable和built_value两个插件。前者更加成熟,后者的功能更加完善以及强大。
目前打算使用built value作为序列化主要使用的代码生成工具。后续继续研究其如何序列化或者反序列化成protobuf
pub地址:json_serializable | Dart Package (pub.dev)
pub地址:built_value | Dart Package (pub.dev)
ORM框架
传统的sqflite需要手写sql代码,是不符合实际开发的效率需求的,因此,我们需要使用ORM框架来简化程序与数据库进行交互,目前主要考虑的是floor框架。
具体使用方式可以参考:Flutter floor数据库类orm插件使用详解 - 掘金