Flutter 状态管理:使用 Provider、Riverpod、flutter_bloc 及更多技术构建电影应用

这个参考项目展示了如何在 Flutter 中使用不同的状态管理技术来实现一个(受 Netflix 启发的)电影应用

Movie app preview

该项目使用 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

业务逻辑和屏幕流程对于每个应用都是相同的,但语义会根据使用的状态管理包而变化。这使得比较和对比不同的解决方案变得容易。

支持的状态管理解决方案

目前支持的状态管理解决方案包括

我计划将来添加更多(欢迎 PR!)。

未来路线图

  • 添加更多屏幕
  • 优化 UI
  • http 替换为 dio 以支持请求取消

如果您希望实现某些功能,请随时打开 issues(但请降低期望,毕竟我是在免费提供这些 ?)。

其他使用的包

该应用的核心包使用了以下包

获取 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