Flutter 中高效的 API 调用

OldBird

实用Tips|2024-11-21|最后更新: 2024-11-21|
type
status
date
slug
summary
tags
category
icon
password
 
 
 
如果你像我一样开始学习 Flutter 开发,你可能会掉进我曾经掉过的坑:代码缺乏结构,把 context 传递给 API 调用,在 UI 层直接调用 API,结果导致代码一团乱麻。虽然应用最终上线了,但每次更新简直就是噩梦。
 
<ins/>
在几年的 Flutter 开发之旅后,我终于可以自信地说,现在我的代码已经不再是“一锅粥”了。在这篇文章中,我将分享一种清晰的代码组织方式,重点是如何进行 API 调用并将其与我最喜欢的状态管理解决方案(Bloc)结合起来。
慢着!我知道你可能不喜欢 Bloc,但请相信我,这种方法同样适用于其他状态管理技术,例如 Provider、GetX、Stacked,甚至是 Riverpod(🤮)。
notion image
需要强调的是,这不是唯一的方法,也不是最好的方法,但绝对是一个不错的代码组织方式。

为什么要组织代码?

因为达斯·维达(Darth Vader)专治写“意大利面条代码”(spaghetti code)的人😄。更重要的是,良好的代码组织和遵循一定的结构可以让开发者的生活更轻松、更高效。
在本文中,我们将使用一些工具,其中包括一个免费 API(API 文档链接)。获取 API 密钥的任务就交给你了,我们接下来就开始动手吧!

定义 API 响应结构

第一步是定义 API 可能返回的每种响应结构。对于本文使用的 API,官方文档已经很好地说明了我们可以期待的返回数据结构。我们先从创建一个通用的响应对象开始:
注意这里的 T 是一个泛型,意味着 ApiResponse 类可以重用以适配不同的数据对象。
我们还需要一个对象来处理数据列表:

创建网络请求抽象层

接下来,我们需要创建一个对象来处理网络调用。我将使用 dio 包,但不是直接使用,而是通过抽象层封装。这需要我们考虑以下几点:
  1. 设置和删除令牌
  1. 发起请求(支持或不支持 FormData)
  1. 在阻止用户交互的请求中显示加载指示器
  1. 处理异常
基于这些需求,我们定义了以下接口:
枚举 MethodType 的定义如下:

实现网络请求类

以下是基于 dio 的实现类:
 
接下来,我们将通过更具体的例子展示如何利用刚刚实现的 DioClient 来调用 API 并处理响应。

定义模型类

我们需要定义一些模型类来匹配 API 返回的数据结构。在这里,以电影的模型为例:
通过使用 json_serializable,我们可以自动生成序列化和反序列化的代码,以节省手动编写的时间。确保你已在 pubspec.yaml 中配置了以下依赖:
运行以下命令生成序列化代码:

创建服务类

接下来,我们需要创建一个服务类,专门用于与 API 交互并返回我们定义的模型类。这将封装我们的 API 调用逻辑并保持代码整洁。
<ins/>

集成状态管理(以 Bloc 为例)

在 Bloc 中,我们通常将状态分为三种类型:初始状态、加载中状态和加载完成/失败状态。以下是电影 Bloc 的实现:

1. 定义 Bloc 状态

2. 定义 Bloc 事件

3. 实现 Bloc


在 UI 层显示数据

在 Flutter 的 UI 层,我们可以使用 BlocBuilder 或 BlocConsumer 来监听状态并更新界面。以下是一个简单的例子:

最终整合

  1. main.dart 中初始化依赖并运行应用:

结语

通过以上步骤,我们成功实现了一个整洁的 API 调用结构,同时集成了 Bloc 状态管理。这种方法不仅使代码更易于维护,还能让团队协作更加高效。
如果你想进一步优化,可以尝试添加错误处理、缓存机制,以及更复杂的状态管理逻辑。
 
Loading...