【openHarmonyos】开源鸿蒙跨平台训练营DAY8:Flutter 鸿蒙开发指南+轮播图数据获取
│└── home.dart# 数据模型(含工厂函数)│└── DioRequest.dart# 网络请求工具。│└── home.dart# API封装。│└── HmSlider.dart# 轮播图组件。└── index.dart# 首页(调用API)│└── index.dart# 全局常量。│(更新UI)│。│(工厂函数)│。
一、环境配置准备
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 |
| 返回数据格式: |
{
"code": "1",
"message": "success",
"result": [
{"id": "1", "imgUrl": "https://xxx.com/1.jpg"},
{"id": "2", "imgUrl": "https://xxx.com/2.jpg"}
]
}
二、代码实现
2.1 安装 dio 库
flutter pub add dio
打开项目根目录下的pubspec.yaml文件
在dependencies部分添加dio的最新版本依赖(当前最新稳定版为5.9.1):
dependencies:
dio: ^5.9.1
2.2 创建常量类
在 lib/constants/index.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:
// 基于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
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 文件,用于封装首页相关 API 接口。
// 封装轮播图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
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 = [];
void initState() {
super.initState();
_getBannerList();
}
/// 获取轮播图数据
void _getBannerList() async {
try {
_bannerList = await getBannerListAPI();
setState(() {});
} catch (e) {
print('获取轮播图数据失败: $e');
}
}
// ...
}
2.7 轮播图支持网络图片功能
修改文件路径:lib/components/Home/HmSlider.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,用于集中管理全局和HTTP相关常量 |
| 网络封装 | 通过DioRequest单例配合拦截器实现网络请求的统一管理和预处理 |
| 数据转换 | 使用factory工厂函数实现原始数据与模型对象的双向转换 |
| API封装 | 对接口返回数据进行类型强校验,确保数据类型安全 |
| UI集成 | 在initState生命周期发起API请求,通过setState完成数据驱动UI更新 |
核心要点:
- 基于 dio 库实现网络请求功能
- 封装通用请求工具类,统一处理:
- HTTP 状态码校验
- 业务状态码解析
- 采用 factory 模式实现 JSON 数据到业务对象的转换
- API 层负责返回标准化数据结构
- 组件支持:
- 网络图片加载
- 异常状态处理
欢迎加入开源鸿蒙跨平台社区: https://openharmonycrossplatform.csdn.net
更多推荐
所有评论(0)