首先,欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net,获取更多Flutter鸿蒙开发相关教程、技术支持和开源资源,与开发者们一起交流学习、共同进步。
本文参考Flutter鸿蒙开发指南(八):获取轮播图数据-CSDN博客
本文记录操作过程以及遇到的问题
在上一节中,我们完成了轮播图的细节优化,实现了「轮播图顶部搜索框」和「底部导航指示灯」两个核心交互组件。这一节,我们将聚焦核心需求------获取真实的轮播图API数据,通过Dio网络请求工具,完成接口请求、数据解析、数据渲染的全流程实现,让轮播图展示真实的业务海报内容。
一、前置准备
获取轮播图API数据前,需要完成3个核心前置操作:安装网络请求工具Dio、定义相关常量(基础地址、接口地址等)、封装网络请求工具,为后续接口调用做好铺垫。以下是详细步骤和说明,每一步都需严格执行,避免后续出现请求失败、数据解析异常等问题。
1.1 前置准备完整步骤
按以下顺序执行前置操作,确保每一步都落地完成,为API数据获取打好基础:
- 安装Dio网络请求插件:用于发送HTTP请求,获取API接口数据(Flutter中最常用的网络请求工具);
- 定义常量数据:统一管理基础接口地址、请求超时时间、业务状态码、轮播图接口地址,便于后续维护和修改;
- 封装网络请求工具:对Dio进行二次封装,配置基础地址、超时时间、拦截器,简化后续接口调用流程;
- 请求工具进一步解构:处理HTTP状态码和业务状态码,统一拦截异常请求,返回真实可用的数据;
- 类工厂转化动态类型:将接口返回的JSON动态数据,转化为我们定义的BannerItem实体类对象,便于数据渲染;
- 封装请求API调用工厂函数:单独封装轮播图接口调用方法,分离业务逻辑和请求逻辑,提升代码可读性和可维护性;
- 初始化数据更新状态:在首页初始化时调用API请求方法,获取数据后更新页面状态,实现轮播图数据渲染。
1.2 接口请求成功示例
本次开发使用的真实轮播图API接口信息如下,可提前在浏览器或接口测试工具(如Postman)中测试,确认接口可正常返回数据,避免因接口问题导致开发受阻:
- 接口基础地址:https://meikou-api.itheima.net
- 轮播图地址(get):https://meikou-api.itheima.net/home/banner
- 接口返回格式:如下图所示

1.3 Dio插件安装方法
Dio是Flutter中功能强大的网络请求插件,支持GET、POST等多种请求方式,拦截器、超时设置等常用功能,安装步骤如下:
-
打开项目根目录的终端(或Android Studio底部的Terminal面板);
-
输入以下安装命令,按下回车,等待插件下载完成:
bashflutter pub add dio -
验证安装成功:命令执行完成后,终端会显示"added dio: ^x.x.x"(版本号可能不同),同时项目的pubspec.yaml文件中会自动新增dio的依赖配置,无需手动修改。

二、轮播图API请求实现
完成前置准备和Dio安装后,我们开始分步实现轮播图API数据获取,按"定义常量 → 封装请求工具 → 数据类型转换 → 封装API → 页面调用渲染"的顺序执行。
2.1 编写常量类(统一管理配置)
核心目的:将接口基础地址、超时时间、业务状态码、接口地址等常量,统一放在一个文件中管理,后续若需修改(如切换接口环境),只需修改该文件,无需修改所有调用处,提升代码可维护性。
操作步骤:lib目录下的constants文件夹,在该文件夹下新建index.dart文件,编写如下代码:
Dart
//全局状态
class GlobalConstants {
//基础地址
static const String BASE_URL = "https://meikou-api.itheima.net/";
//超时时间
static const int TIME_OUT = 10;
//成功状态
static const String SUCCESS_CODE = "1";
}
//存放请求地址接口的常量
class HttpConstants{
//轮播图接口
static const String BANNER_LIST = "/home/banner";
}
2.2 封装Dio网络请求工具
核心目的:对Dio进行二次封装,配置基础地址、超时时间、拦截器,统一处理请求异常、响应结果,简化后续接口调用流程(无需每次调用接口都配置基础地址、超时时间)。
操作步骤:在lib/utils文件夹下新建DioRequest.dart文件,编写如下代码(完整封装,可直接复制使用):
Dart
//基于Dio进行二次封装
import 'package:dio/dio.dart';
import 'package:xiuhu_mall/constants/index.dart';
class DioRequest {
final _dio = Dio(); //dio请求对象
//基础地址拦截器
DioRequest() {
_dio.options
..baseUrl = GlobalConstants.BASE_URL
..connectTimeout = Duration(seconds: GlobalConstants.TIME_OUT)
..sendTimeout = Duration(seconds: GlobalConstants.TIME_OUT)
..receiveTimeout = Duration(seconds: GlobalConstants.TIME_OUT);
//拦截器-三个
_addInterceptor();
}
// 添加拦截器
void _addInterceptor() {
_dio.interceptors.add(InterceptorsWrapper(onRequest: (request, handler) {
handler.next(request);
}, onResponse: (response, handler) {
//http状态码 200 300
if (response.statusCode! >= 200 && response.statusCode! < 300) {
handler.next(response);
return;
}
handler.reject(DioException(requestOptions: response.requestOptions));
}, onError: (error, handler) {
handler.reject(error);
}));
}
//GET请求方法
Future<dynamic> get(String url, {Map<String, dynamic>? params}) async {
try {
final response = await _dio.get(url, queryParameters: params);
return _handleResponse(response);
} catch (e) {
rethrow;
}
}
//进一步处理返回结果的函数
Future<dynamic> _handleResponse(Response<dynamic> task) async {
try {
Response<dynamic> res = await task;
final data = res.data as Map<String, dynamic>; //data才是我们真实的接口返回的数据
if (data["code"] == GlobalConstants.SUCCESS_CODE) {
//如果等于1 才认定http状态和业务状态均为正常 就可以正常的放行通过
return data["result"]; //只要result结果
}
//抛出异常
throw Exception(data["message"] ?? "加载数据异常");
} catch (e) {
throw Exception(e);
}
}
}
// 单例对象
final dioRequest = DioRequest();
//dio请求工具发出请求->返回的数据通过Response<dynamic>.data
//把所有的接口的data解放出来 拿到真正的数据 要判断业务状态码是不是等于1
封装逻辑说明:
- 单例对象:final dioRequest = DioRequest(); 确保全局只有一个Dio请求对象,避免重复创建导致的性能损耗;
- 拦截器作用:请求拦截可添加token、请求头;响应拦截统一处理HTTP状态码;错误拦截统一捕获请求异常;
- _handleResponse方法:核心是区分"网络层面成功"和"业务层面成功",只有HTTP状态码200~299且业务状态码=1,才返回真实数据;
- 异常处理:所有异常(请求超时、网络错误、业务异常、解析异常)都被捕获并抛出,让调用处统一处理(如提示用户)。
2.3 转换动态类型(JSON转实体类)
核心目的:接口返回的是JSON动态数据(Map类型),而我们轮播图组件需要的是BannerItem实体类对象的列表,因此需要通过工厂函数,将JSON数据转化为BannerItem对象,便于数据渲染和类型安全。
操作步骤:修改lib/viewmodels/home.dart文件(原有BannerItem类),添加工厂函数formJSON,完整代码如下:
Dart
class BannerItem {
String id;
String imgUrl;
BannerItem({required this.id, required this.imgUrl});
//扩展一个工厂函数 一般用factory来声明 一般用来创建实例对象
factory BannerItem.formJSON(Map<String, dynamic> json) {
//必须返回一个BannerItem对象
return BannerItem(id: json["id"] ?? "", imgUrl: json["imgUrl"] ?? "");
}
}
//每一个轮播图具体类型
//flutter必须强制转换,没有隐式转化
2.4 封装API调用函数
核心目的:单独封装轮播图接口调用方法,将"网络请求"与"页面渲染"分离,提升代码可读性和可维护性,后续若需修改接口调用逻辑,只需修改该方法,无需修改页面代码。
操作步骤:在lib/api目录下新建home.dart文件,编写如下代码:
Dart
//封装一个api 目的是返回业务侧要的数据结构
import 'package:xiuhu_mall/constants/index.dart';
import 'package:xiuhu_mall/utils/DioRequest.dart';
import 'package:xiuhu_mall/viewmodels/home.dart';
Future<List<BannerItem>> getBannerListAPI() async {
//返回请求
final tt =
((await dioRequest.get(HttpConstants.BANNER_LIST)) as List).map((item) {
return BannerItem.formJSON(item as Map<String, dynamic>);
}).toList();
return tt;
}
2.5 页面调用API,渲染数据
核心目的:在首页初始化时,调用封装好的getBannerListAPI()方法,获取真实的轮播图API数据,更新页面状态,将数据传递给轮播图组件(HmSlider),实现真实数据渲染。
操作步骤:修改lib/pages/Home/index.dart文件,删除本地模拟数据,新增API调用逻辑,完整代码如下:
Dart
import 'package:flutter/cupertino.dart';
import 'package:xiuhu_mall/api/home.dart';
import 'package:xiuhu_mall/components/Home/HmCategory.dart';
import 'package:xiuhu_mall/components/Home/HmHot.dart';
import 'package:xiuhu_mall/components/Home/HmMoreList.dart';
import 'package:xiuhu_mall/components/Home/HmSlider.dart';
import 'package:xiuhu_mall/components/Home/HmSuggestion.dart';
import 'package:xiuhu_mall/viewmodels/home.dart';
class HomeView extends StatefulWidget {
const HomeView({super.key});
@override
State<HomeView> createState() => _HomeViewState();
}
class _HomeViewState extends State<HomeView> {
List<BannerItem> _bannerList = [
// BannerItem(
// id: "1",
// imgUrl: "https://yjy-teach-oss.oss-cn-beijing.aliyuncs.com/meituan/1.jpg",
// ),
// BannerItem(
// id: "2",
// imgUrl: "https://yjy-teach-oss.oss-cn-beijing.aliyuncs.com/meituan/2.png",
// ),
// BannerItem(
// id: "3",
// imgUrl: "https://yjy-teach-oss.oss-cn-beijing.aliyuncs.com/meituan/3.jpg",
// ),
];
//获取滚动容器的内容
List<Widget> _getScrollChildren() {
return [
//包裹普通widget的sliver家族的组件内容
SliverToBoxAdapter(child: HmSlider(bannerList: _bannerList)), //轮播图组件
//放置分类组件
SliverToBoxAdapter(child: SizedBox(height: 10)),
//SliverGrid SliverList指南纵向排列
SliverToBoxAdapter(child: HmCategory()), //分类组件
SliverToBoxAdapter(child: SizedBox(height: 10)),
SliverToBoxAdapter(child: HmSuggestion()), //推荐组件
SliverToBoxAdapter(child: SizedBox(height: 10)),
//Flex和Expanded配合起来可以均分比例
SliverToBoxAdapter(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Flex(
direction: Axis.horizontal,
children: [
Expanded(child: HmHot()),
SizedBox(
width: 10,
),
Expanded(child: HmHot()),
],
)),
),
SliverToBoxAdapter(child: SizedBox(height: 10)),
HmMorelist(), //无限滚动列表
];
}
@override
void initState() {
// TODO: implement initState
super.initState();
_getBannederList();
}
void _getBannederList() async {
_bannerList = await getBannerListAPI();
setState(() {});
}
@override
Widget build(BuildContext context) {
//CustomScrollview要求:必须是sliver家族的内容
return CustomScrollView(slivers: _getScrollChildren());
}
}
核心修改点说明:
- 删除本地模拟数据:将原有_bannerList中的本地模拟数据删除,初始化为空列表;
- initState中调用API:initState是页面初始化生命周期方法,在此处调用_getBannerList(),确保页面加载时就获取轮播图数据;
- 异步请求处理:_getBannerList()方法添加async/await,处理API异步请求(API请求是耗时操作,需等待结果返回);
- 异常处理:添加try/catch捕获异常,避免请求失败导致页面崩溃,同时可设置默认数据,提升用户体验;
- setState刷新页面:获取到数据后,通过setState更新_bannerList,触发页面重新渲染,轮播图组件将展示真实API数据。
2.6 查看API请求效果:
真实API数据渲染的轮播图效果:

三、提交代码
完成轮播图API数据获取的所有功能开发、测试后,执行以下Git命令,将代码提交到远程仓库,保存当前开发进度
bash
git add .
git commit -m "完成获取轮播图数据"
git push
四、总结
本文衔接上一节轮播图细节优化内容,实现了电商App首页「轮播图API数据获取」的开发,核心总结如下:
- 核心流程:本次开发的核心流程为「安装Dio → 定义常量 → 封装Dio请求 → JSON转实体类 → 封装API → 页面调用API → 数据渲染」;
- 核心知识点:Dio插件的安装与封装、拦截器的使用、async/await异步请求处理、JSON与实体类的转换、页面生命周期(initState)的使用、异常处理与默认数据设置;
- 代码规范:通过常量类统一管理配置、通过API封装类分离业务逻辑、通过实体类保证类型安全,提升了代码的可读性、可维护性和可复用性;
注意事项:
- 确保Dio插件安装成功,且依赖配置正确;
- 接口地址拼接正确;
- 工厂函数字段与接口返回字段一致,且设置默认值,避免空指针异常;
- 所有异步请求必须添加异常处理,避免页面崩溃;
- 获取数据后必须调用setState,否则页面无法刷新渲染数据。
功能延伸:
- 添加加载状态:请求数据时显示加载动画,请求完成后隐藏;
- 添加错误提示:请求失败时,显示Toast提示用户"加载轮播图失败";
- 添加缓存机制:将获取到的轮播图数据缓存到本地,下次打开页面优先加载缓存数据,提升加载速度;
- 扩展其他接口:按照本次封装流程,可快速实现首页分类、推荐等其他业务接口的数据获取。
至此,轮播图获取真实的API数据功能已完善。