Flutter鸿蒙开发指南:获取轮播图网络数据并实现展示
在前面的Flutter鸿蒙开发内容中,我们已经完成了轮播图的UI搭建,包含搜索框、导航指示器等基础组件的实现。本文将聚焦轮播图网络数据的获取与渲染,从环境准备、网络请求封装到数据解析、页面展示,完整实现从API接口拉取真实轮播图数据并在鸿蒙端展示的功能,全程基于Dio库实现网络请求,遵循Flutter工程化开发规范。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net


- Flutter鸿蒙开发指南:获取轮播图网络数据并实现展示
-
- 一、前置准备
-
- [1.1 核心实现步骤](#1.1 核心实现步骤)
- [1.2 接口信息说明](#1.2 接口信息说明)
- 二、代码实现
-
- [2.1 安装Dio网络请求库](#2.1 安装Dio网络请求库)
- [2.2 创建全局常量类](#2.2 创建全局常量类)
- [2.3 二次封装Dio网络请求工具](#2.3 二次封装Dio网络请求工具)
- [2.4 数据模型添加工厂函数](#2.4 数据模型添加工厂函数)
- [2.5 封装轮播图API调用方法](#2.5 封装轮播图API调用方法)
- [2.6 在页面中调用API并更新UI](#2.6 在页面中调用API并更新UI)
- [2.7 轮播图支持网络图片](#2.7 轮播图支持网络图片)
- 三、数据流程图
- 四、项目工程结构
- 五、总结
一、前置准备
1.1 核心实现步骤
本次开发的核心流程遵循工程化思想,分步骤实现网络请求与数据渲染,确保代码的可维护性和复用性:
- 安装Dio网络请求库,实现HTTP请求基础能力
- 定义全局常量,统一管理接口地址、超时时间等配置
- 二次封装Dio网络请求工具,封装GET/POST方法及拦截器
- 创建数据模型并添加工厂函数,实现JSON数据与实体类的解析
- 封装轮播图API调用方法,解耦网络请求与页面逻辑
- 在轮播图页面调用API,获取数据并更新UI
- 适配网络图片,完成轮播图的最终展示
1.2 接口信息说明
本次使用的轮播图接口为公开测试接口,请求方式为GET,接口详细信息如下:
| 项目 | 具体值 |
|---|---|
| 接口基础地址 | https://meikou-api.itheima.net/ |
| 轮播图接口路径 | /home/banner |
| 完整请求地址 | https://meikou-api.itheima.net/home/banner |
| 请求方式 | GET |
| 响应数据格式 | JSON |
接口返回数据示例:
json
{
"code": "1",
"message": "success",
"result": [
{"id": "1", "imgUrl": "https://xxx.com/1.jpg"},
{"id": "2", "imgUrl": "https://xxx.com/2.jpg"}
]
}
code:业务状态码,1表示请求成功message:请求结果描述,成功时返回successresult:轮播图核心数据,数组格式,包含图片ID和网络地址
二、代码实现
2.1 安装Dio网络请求库
Dio是Flutter生态中常用的网络请求库,支持拦截器、请求取消、超时配置等功能,适合工程化开发。执行以下命令安装最新稳定版:
bash
flutter pub add dio
安装完成后,pubspec.yaml文件的dependencies节点会自动添加Dio依赖,示例如下(版本号以实际安装为准):
yaml
dependencies:
flutter:
sdk: flutter
dio: ^5.9.1 # Dio网络请求库
添加后执行flutter pub get同步依赖,确保库能正常引入。
2.2 创建全局常量类
为了统一管理项目中的接口配置、常量参数,创建常量类文件,实现一处定义、全局使用 ,减少硬编码问题。
创建文件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";
}
设计说明 :使用static const定义常量的原因
static:无需创建类的实例,直接通过类名访问,简化调用const:编译时常量,值不可修改,避免运行时意外篡改- 全局共享:所有页面和工具类均可引用,节省内存且便于后期维护
2.3 二次封装Dio网络请求工具
原生Dio的调用方式较为零散,本次对其进行二次封装 ,封装通用的GET/POST方法、配置全局拦截器、统一处理响应数据,降低页面层的代码耦合。
创建文件lib/utils/DioRequest.dart,代码如下:
dart
// 基于Dio的网络请求工具类,二次封装实现通用请求能力
import 'package:dio/dio.dart';
import 'package:harmonyos_day_four/constants/index.dart';
class DioRequest {
// 初始化Dio实例
final Dio _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();
}
// 配置Dio拦截器:请求拦截、响应拦截、错误拦截
void _addInterceptor() {
_dio.interceptors.add(InterceptorsWrapper(
// 请求拦截:可在此添加请求头、token等公共参数
onRequest: (request, handler) {
handler.next(request);
},
// 响应拦截:处理HTTP状态码,过滤非200-300的响应
onResponse: (response, handler) {
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;
}
}
// 封装POST请求方法(预留,后续可用于提交数据)
Future<dynamic> post(String url, {dynamic data}) async {
try {
final response = await _dio.post(url, data: data);
return _handleResponse(response);
} catch (e) {
rethrow;
}
}
// 统一处理响应数据:解析业务状态码,返回核心数据
dynamic _handleResponse(Response<dynamic> response) {
final data = response.data as Map<String, dynamic>;
// 判断业务状态码是否成功
if (data["code"] == GlobalConstants.SUCCESS_CODE) {
return data["result"]; // 只返回核心的result数据,简化页面层解析
}
// 业务请求失败时,抛出异常并携带错误信息
throw Exception(data["message"] ?? "加载数据异常");
}
}
// 创建DioRequest单例对象,全局唯一,避免重复创建实例
final dioRequest = DioRequest();
封装亮点:
- 单例模式:全局仅创建一个
DioRequest实例,避免资源浪费 - 全局配置:在构造函数中统一配置基础地址、超时时间,无需重复设置
- 拦截器:实现请求、响应、错误拦截,便于后续扩展请求头、统一错误处理
- 数据过滤:
_handleResponse方法统一处理业务状态码,页面层直接获取核心数据 - 异常抛出:请求失败时抛出异常,便于页面层捕获并处理UI提示
2.4 数据模型添加工厂函数
为了规范JSON数据解析,避免直接在页面层使用[]获取数据导致的空指针问题,创建轮播图数据模型,并添加工厂函数实现JSON转实体类 。
创建文件lib/models/banner_model.dart,代码如下:
dart
// 轮播图数据模型
class BannerModel {
// 轮播图ID
final String id;
// 轮播图网络图片地址
final String imgUrl;
// 构造函数
BannerModel({required this.id, required this.imgUrl});
// 工厂函数:从JSON解析为BannerModel实例
factory BannerModel.fromJson(Map<String, dynamic> json) {
return BannerModel(
id: json["id"] ?? "",
imgUrl: json["imgUrl"] ?? "",
);
}
// 静态方法:将JSON数组解析为BannerModel列表
static List<BannerModel> fromJsonList(List<dynamic> jsonList) {
return jsonList.map((json) => BannerModel.fromJson(json)).toList();
}
}
设计说明:
- 成员变量使用
final,保证不可变性,符合Flutter的不可变设计思想 - 工厂函数
fromJson:实现单个JSON对象到实体类的解析,对空值做默认处理 - 静态方法
fromJsonList:实现JSON数组到实体类列表的解析,直接为轮播图提供数据列表
2.5 封装轮播图API调用方法
为了解耦网络请求与页面逻辑,创建API封装层,专门管理所有接口的调用方法,页面层只需调用方法即可获取数据,无需关注底层请求细节。
创建文件lib/api/banner_api.dart,代码如下:
dart
// 轮播图API封装层,统一管理轮播图相关接口调用
import 'package:harmonyos_day_four/constants/index.dart';
import 'package:harmonyos_day_four/models/banner_model.dart';
import 'package:harmonyos_day_four/utils/DioRequest.dart';
class BannerApi {
// 获取轮播图数据列表
static Future<List<BannerModel>> getBannerList() async {
// 调用DioRequest的GET方法,请求轮播图接口
final result = await dioRequest.get(HttpConstants.BANNER_LIST);
// 将返回的JSON数组解析为BannerModel列表
return BannerModel.fromJsonList(result);
}
}
解耦优势:后续若接口地址、请求方式发生变化,只需修改此文件,所有调用处无需改动,降低维护成本。
2.6 在页面中调用API并更新UI
在之前实现的轮播图页面中,引入封装的API,在页面初始化时请求数据,并通过setState更新UI,实现数据的渲染。
以lib/pages/home_page.dart为例,核心代码如下:
dart
import 'package:flutter/material.dart';
import 'package:harmonyos_day_four/api/banner_api.dart';
import 'package:harmonyos_day_four/models/banner_model.dart';
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
// 轮播图数据列表
List<BannerModel> _bannerList = [];
// 加载状态标识
bool _isLoading = true;
@override
void initState() {
super.initState();
// 页面初始化时调用,获取轮播图数据
_loadBannerData();
}
// 加载轮播图数据
Future<void> _loadBannerData() async {
try {
// 调用API获取数据
final bannerList = await BannerApi.getBannerList();
// 更新状态,渲染UI
setState(() {
_bannerList = bannerList;
_isLoading = false;
});
} catch (e) {
// 捕获异常,更新加载状态并提示错误
setState(() {
_isLoading = false;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("轮播图数据加载失败:$e")),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("首页轮播图")),
body: _isLoading
? // 加载中展示加载圈
const Center(child: CircularProgressIndicator())
: // 数据加载完成后展示轮播图
_bannerList.isEmpty
? const Center(child: Text("暂无轮播图数据"))
: _buildBannerView(),
);
}
// 构建轮播图视图(沿用之前实现的UI代码,替换数据源为_bannerList)
Widget _buildBannerView() {
return PageView.builder(
itemCount: _bannerList.length,
itemBuilder: (context, index) {
final banner = _bannerList[index];
return Image.network(
banner.imgUrl,
fit: BoxFit.cover,
);
},
);
}
}
核心要点:
- 在
initState中调用数据加载方法,保证页面初始化时立即请求数据 - 增加加载状态
_isLoading,优化用户体验,加载中展示加载圈 - 增加异常捕获,数据加载失败时给出Toast提示,避免页面崩溃
- 轮播图UI的数据源替换为网络请求获取的
_bannerList,实现数据驱动UI
2.7 轮播图支持网络图片
Flutter中通过Image.network组件加载网络图片,直接传入图片的网络地址即可,上述代码中已实现:
dart
Image.network(
banner.imgUrl, // 从数据模型中获取网络图片地址
fit: BoxFit.cover, // 图片适配方式,铺满容器
// 可添加加载中和加载失败的占位图
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return const Center(child: CircularProgressIndicator());
},
errorBuilder: (context, error, stackTrace) {
return const Center(child: Icon(Icons.image_not_supported));
},
);
可通过loadingBuilder和errorBuilder添加占位图,进一步优化网络图片的加载体验。

三、数据流程图
本次轮播图数据获取的整体流程遵循分层设计,数据流转清晰,各层职责明确,流程图如下:
用户进入页面 → 页面初始化调用API → API层调用网络工具类 → Dio发送GET请求 → 接口返回JSON数据
→ 网络工具类处理业务状态码 → API层解析为实体类列表 → 页面层接收数据并更新UI → 轮播图渲染网络图片
各层职责:
- 页面层:负责UI展示、用户交互、调用API获取数据
- API层:封装接口调用方法,解耦页面与网络请求
- 网络工具层:封装Dio,实现通用的网络请求能力
- 模型层:实现JSON数据与实体类的解析,规范数据格式
- 常量层:统一管理配置参数,避免硬编码
四、项目工程结构
本次开发后,项目的核心工程结构如下(按功能分层),符合Flutter工程化开发规范,便于团队协作和后期扩展:
lib/
├── api/ # API封装层:所有接口调用方法
│ └── banner_api.dart # 轮播图接口封装
├── constants/ # 常量层:全局配置、接口地址
│ └── index.dart # 全局常量定义
├── models/ # 模型层:数据实体类
│ └── banner_model.dart # 轮播图数据模型
├── pages/ # 页面层:所有业务页面
│ └── home_page.dart # 首页(轮播图页面)
├── utils/ # 工具层:通用工具类
│ └── DioRequest.dart # Dio网络请求工具
└── main.dart # 项目入口文件
五、总结
本文完成了Flutter鸿蒙开发中轮播图网络数据获取与展示的完整实现,核心知识点和开发规范总结如下:
- 网络请求:使用Dio库实现HTTP请求,通过二次封装提升代码复用性和可维护性
- 工程化设计:采用分层开发思想,将页面、API、网络、模型、常量分层管理,解耦各模块逻辑
- 数据解析:创建实体类并添加工厂函数,规范JSON数据解析,避免空指针问题
- 异常处理:在网络请求、数据解析、页面调用等环节增加异常捕获,保证应用的稳定性
- 体验优化:增加加载状态、异常提示、网络图片占位图,提升用户体验
- 鸿蒙适配:本次开发的代码可直接在鸿蒙端运行,无需额外修改,符合Flutter跨平台特性
通过本次开发,不仅实现了轮播图的网络数据渲染,还掌握了Flutter工程化开发的核心思想,后续可将此套方案复用至其他业务模块的网络请求开发中。在实际项目中,还可在此基础上扩展请求缓存、token鉴权、多环境配置等功能,进一步提升项目的实用性。
✨ 坚持用 清晰的图解 +易懂的硬件架构 + 硬件解析, 让每个知识点都 简单明了 !
🚀 个人主页 :一只大侠的侠 · CSDN
💬 座右铭 : "所谓成功就是以自己的方式度过一生。"
