Flutter 状态管理:使用 Provider、Riverpod、flutter_bloc 及更多技术构建电影应用
这个参考项目展示了如何在 Flutter 中使用不同的状态管理技术来实现一个(受 Netflix 启发的)电影应用
该项目使用 TMDB API 获取电影列表,并包含分页和本地存储等功能。
运行项目
运行前,请参阅有关如何 获取 TMDB API 密钥 的说明。
另外,请确保运行在 **Flutter Beta** 版本上。
应用概览
该应用程序包含三个主要屏幕:正在上映、收藏夹 和 个人资料。
首次启动时,应用会要求用户创建个人资料。
正在上映 页面从 TMDB API 加载当前电影列表。结果是分页的,滚动到底部会导致加载下一页。
每部电影都使用从 API 获取的图片 URL 以海报形式显示。您可以点击 ❤️ 图标将电影添加为收藏(针对选定的个人资料),此偏好设置将持久化到本地磁盘。
打开 收藏夹 页面,查看当前选定个人资料的收藏列表。
使用 个人资料 页面创建其他个人资料并更新当前选定的个人资料(这受到了 Netflix UI 的启发)。
功能
- “正在上映”电影(含分页)
- 将收藏夹保存到观看列表
- 多个个人资料(类似 Netflix)
- 本地数据持久化(电影、收藏夹、个人资料),使用 Sembast
将这些功能结合起来,可以成为 Flutter 状态管理的一个有趣的案例研究。
应用结构
此应用旨在比较和对比多种状态管理方法。设计了 **高度可组合** 的架构来实现这一点。
项目文件夹结构如下:
/apps
/flutter_bloc
/riverpod
/provider
... and more
/packages
/core
/lib
/api
/models
/app_models
/app_state
/tmdb
/persistence
/ui
apps 文件夹内的每个文件夹都是一个 Flutter 项目,它使用特定的状态管理包实现了相同的应用。
所有公共功能都位于 packages/core。这包括一个 TMDB API 包装器,以及模型类和支持的序列化代码(如果需要)。
persistence 文件夹包含一个由所有应用使用的 DataStore 抽象类,以及一个具体的 SembastDataStore 类,用于将数据读写到本地存储(使用 Sembast 作为 NoSQL 数据库)。
ui 文件夹包含所有由所有应用共享的自定义小部件。这些小部件 **不包含任何业务逻辑**,而是设计用于 **展示应用 UI** 和 **暴露回调** 供应用程序代码集成(类似于内置的 Flutter 小部件)。
所有逻辑都存在于应用本身。所有应用都有完全相同的文件夹。
lib
/app
/app_startup
/create_profile
/favourites
/now_playing
/profile_selection
业务逻辑和屏幕流程对于每个应用都是相同的,但语义会根据使用的状态管理包而变化。这使得比较和对比不同的解决方案变得容易。
支持的状态管理解决方案
目前支持的状态管理解决方案包括
- Provider(使用
StateNotifier) - flutter_bloc(使用
Cubit) - Riverpod(使用
StateNotifier) - States Rebuilder
我计划将来添加更多(欢迎 PR!)。
未来路线图
- 添加更多屏幕
- 优化 UI
- 将
http替换为dio以支持请求取消
如果您希望实现某些功能,请随时打开 issues(但请降低期望,毕竟我是在免费提供这些 ?)。
其他使用的包
该应用的核心包使用了以下包
- Freezed 用于应用状态,json_annotation 用于数据序列化
- Sembast 用于本地数据持久化
- http 用于 API 客户端
- rxdart 用于组合流
获取 TMDB API 密钥
该项目使用 TMDB API 获取最新的电影数据。
在运行应用之前,您需要 在 TMDB 网站上注册,然后在 API 设置页面 获取 API 密钥。
获取密钥后,在 packages/core/lib/api 目录下创建一个 api_keys.dart 文件,并添加您的密钥
// api_keys.dart
String tmdbApiKey = "your-api-key";
恭喜,您已准备就绪。?
注意:从不安全的 HTTP 端点加载图片
TMBD API 返回的数据指向的图片 URL 使用的是 http 而不是 https。为了使图片能够正确加载,已进行以下更改
Android
在 android/app/src/main/res/xml/network_security_config.xml 创建一个文件,内容如下
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true" />
</network-security-config>
在 AndroidManifest.xml 的 application 标签中添加此项
android:networkSecurityConfig="@xml/network_security_config"
iOS
在 ios/Runner/info.pList 中添加以下内容
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
更多信息请参见此处
鸣谢
此项目受到了 Flutter 社区的 flutter_architecture_samples 的启发。
许可证:MIT
GitHub
https://github.com/bizz84/movie_app_state_management_flutter
