Flutter鸿蒙开发指南(八):获取轮播图数据

🌸你好呀!我是 lbb小魔仙
🌟 感谢陪伴~ 小白博主在线求友
🌿 跟着小白学Linux/Java/Python
📖 专栏汇总:
《Linux》专栏 | 《Java》专栏 | 《Python》专栏

前言
在上一篇《Flutter鸿蒙开发指南(七):轮播图搜索框和导航指示器》中,我们实现了轮播图的UI展示。本篇文章将介绍如何通过API接口获取真实的轮播图数据,实现网络请求功能。
参考文章: Flutter鸿蒙开发指南(八):获取轮播图数据
一、前置准备
1.1 实现步骤
1. 安装 dio 库
2. 定义常量(基础地址、超时时间、业务状态、请求地址)
3. 封装网络请求工具(DioRequest)
4. 数据模型添加工厂函数
5. 封装 API 调用
6. 页面中调用 API 并更新 UI
1.2 接口信息
| 项目 | 值 |
|---|---|
| 基础地址 | https://meikou-api.itheima.net/ |
| 轮播图接口 | /home/banner (GET) |
| 完整地址 | https://meikou-api.itheima.net/home/banner |
返回数据格式:
json
{
"code": "1",
"message": "success",
"result": [
{"id": "1", "imgUrl": "https://xxx.com/1.jpg"},
{"id": "2", "imgUrl": "https://xxx.com/2.jpg"}
]
}
二、代码实现
2.1 安装 dio 库
bash
flutter pub add dio
pubspec.yaml:
yaml
dependencies:
dio: ^5.9.1
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 封装网络请求工具
创建 lib/utils/DioRequest.dart:
dart
// 基于Dio进行二次封装
import 'package:dio/dio.dart';
import 'package:harmonyos_day_four/constants/index.dart';
class DioRequest {
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();
}
// 添加拦截器
void _addInterceptor() {
_dio.interceptors.add(InterceptorsWrapper(
onRequest: (request, handler) {
// 请求拦截器
handler.next(request);
},
onResponse: (response, handler) {
// 响应拦截器:处理HTTP状态码
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;
}
}
// 进一步处理返回结果的函数:处理业务状态码
Future<dynamic> _handleResponse(Response<dynamic> task) async {
try {
Response<dynamic> res = await task;
final data = res.data as Map<String, dynamic>;
// 判断业务状态码是否等于1
if (data["code"] == GlobalConstants.SUCCESS_CODE) {
return data["result"]; // 只返回result数据
}
throw Exception(data["message"] ?? "加载数据异常");
} catch (e) {
throw Exception(e);
}
}
}
// 单例对象
final dioRequest = DioRequest();
封装要点:
- 单例模式 - 全局共享一个实例
- 拦截器 - 统一处理HTTP状态码和业务状态码
- 错误处理 - 统一异常抛出
2.4 数据模型添加工厂函数
修改 lib/viewmodels/home.dart:
dart
class BannerItem {
String id;
String imgUrl;
BannerItem({required this.id, required this.imgUrl});
// 工厂函数:从JSON创建对象
factory BannerItem.formJSON(Map<String, dynamic> json) {
return BannerItem(
id: json["id"] ?? "",
imgUrl: json["imgUrl"] ?? "",
);
}
}
工厂函数说明:
factory关键字用于声明工厂构造函数- 不一定创建新实例,可以返回缓存实例
- 常用于JSON反序列化
2.5 封装 API 调用
创建 lib/api/home.dart:
dart
// 封装轮播图API,返回业务侧需要的数据结构
import 'package:harmonyos_day_four/constants/index.dart';
import 'package:harmonyos_day_four/utils/DioRequest.dart';
import 'package:harmonyos_day_four/viewmodels/home.dart';
/// 获取轮播图列表数据
Future<List<BannerItem>> getBannerListAPI() async {
// 发起请求并转换数据
final result = ((await dioRequest.get(HttpConstants.BANNER_LIST)) as List)
.map((item) {
return BannerItem.formJSON(item as Map<String, dynamic>);
}).toList();
return result;
}
封装优势:
- 业务层无需关心网络请求细节
- 直接返回强类型的数据结构
- 便于维护和测试
2.6 页面中调用 API
修改 lib/pages/home/index.dart:
dart
import 'package:flutter/cupertino.dart';
import 'package:harmonyos_day_four/api/home.dart';
import 'package:harmonyos_day_four/components/Home/HmSlider.dart';
// ...其他导入
class _HomeViewState extends State<HomeView> {
// 轮播图数据(从API获取)
List<BannerItem> _bannerList = [];
@override
void initState() {
super.initState();
_getBannerList();
}
/// 获取轮播图数据
void _getBannerList() async {
try {
_bannerList = await getBannerListAPI();
setState(() {});
} catch (e) {
print('获取轮播图数据失败: $e');
}
}
// ...
}
2.7 轮播图支持网络图片
修改 lib/components/Home/HmSlider.dart:
dart
Widget _getSlider() {
final double screenWidth = MediaQuery.of(context).size.width;
// 如果没有数据,显示加载中
if (widget.bannerList.isEmpty) {
return SizedBox(
width: screenWidth,
height: 300,
child: Container(
color: Colors.grey[300],
child: const Center(
child: CircularProgressIndicator(),
),
),
);
}
return SizedBox(
width: screenWidth,
height: 300,
child: PageView.builder(
controller: _pageController,
onPageChanged: (int index) {
setState(() {
_currentIndex = index;
});
},
itemCount: widget.bannerList.length,
itemBuilder: (context, index) {
return Image.network(
widget.bannerList[index].imgUrl,
fit: BoxFit.cover,
width: screenWidth,
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return Container(
color: Colors.grey[200],
child: Center(
child: CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes != null
? loadingProgress.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes!
: null,
),
),
);
},
errorBuilder: (context, error, stackTrace) {
return Container(
color: Colors.grey[300],
child: const Center(
child: Icon(Icons.broken_image, size: 50),
),
);
},
);
},
),
);
}
三、数据流程图
┌─────────────┐
│ HomeView │
│ (initState)│
└──────┬──────┘
│
▼
┌─────────────┐
│getBannerListAPI│
└──────┬──────┘
│
▼
┌─────────────┐
│ dioRequest │
│ .get() │
└──────┬──────┘
│
▼
┌─────────────┐
│ API Server │
│ /home/banner│
└──────┬──────┘
│
▼
┌─────────────┐
│_handleResponse│
│(检查状态码) │
└──────┬──────┘
│
▼
┌─────────────┐
│formJSON() │
│(工厂函数) │
└──────┬──────┘
│
▼
┌─────────────┐
│ setState │
│ (更新UI) │
└─────────────┘

四、项目结构
lib/
├── api/
│ └── home.dart # API封装
├── constants/
│ └── index.dart # 全局常量
├── utils/
│ └── DioRequest.dart # 网络请求工具
├── viewmodels/
│ └── home.dart # 数据模型(含工厂函数)
├── components/Home/
│ └── HmSlider.dart # 轮播图组件
└── pages/home/
└── index.dart # 首页(调用API)
五、总结
本文实现了Flutter鸿蒙项目中的网络请求功能,主要内容包括:
| 模块 | 功能 |
|---|---|
| 常量管理 | GlobalConstants、HttpConstants |
| 网络封装 | DioRequest单例 + 拦截器 |
| 数据转换 | factory工厂函数 |
| API封装 | 返回强类型数据 |
| UI集成 | initState调用API + setState更新 |
关键要点:
- 使用
dio库进行网络请求 - 封装请求工具,统一处理HTTP状态码和业务状态码
- 使用
factory函数实现JSON到对象的转换 - API层返回业务层需要的数据结构
- 组件支持网络图片加载和错误处理
项目地址: https://atomgit.com/lbbxmx111/haromyos_day_four
参考资料
感谢阅读! 如果本文对你有帮助,请点赞收藏。有问题欢迎评论区交流!
欢迎加入开源鸿蒙跨平台社区: https://openharmonycrossplatform.csdn.net
📕个人领域 :Linux/C++/java/AI
🚀 个人主页 :有点流鼻涕 · CSDN
💬 座右铭 : "向光而行,沐光而生。"
