Flutter开源鸿蒙跨平台训练营 Day8获取轮播图网络数据并实现展示

Flutter鸿蒙开发指南:获取轮播图网络数据并实现展示

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

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net


一、前置准备

1.1 核心实现步骤

本次开发的核心流程遵循工程化思想,分步骤实现网络请求与数据渲染,确保代码的可维护性和复用性:

  1. 安装Dio网络请求库,实现HTTP请求基础能力
  2. 定义全局常量,统一管理接口地址、超时时间等配置
  3. 二次封装Dio网络请求工具,封装GET/POST方法及拦截器
  4. 创建数据模型并添加工厂函数,实现JSON数据与实体类的解析
  5. 封装轮播图API调用方法,解耦网络请求与页面逻辑
  6. 在轮播图页面调用API,获取数据并更新UI
  7. 适配网络图片,完成轮播图的最终展示

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:请求结果描述,成功时返回success
  • result:轮播图核心数据,数组格式,包含图片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定义常量的原因

  1. static:无需创建类的实例,直接通过类名访问,简化调用
  2. const:编译时常量,值不可修改,避免运行时意外篡改
  3. 全局共享:所有页面和工具类均可引用,节省内存且便于后期维护

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();

封装亮点

  1. 单例模式:全局仅创建一个DioRequest实例,避免资源浪费
  2. 全局配置:在构造函数中统一配置基础地址、超时时间,无需重复设置
  3. 拦截器:实现请求、响应、错误拦截,便于后续扩展请求头、统一错误处理
  4. 数据过滤:_handleResponse方法统一处理业务状态码,页面层直接获取核心数据
  5. 异常抛出:请求失败时抛出异常,便于页面层捕获并处理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();
  }
}

设计说明

  1. 成员变量使用final,保证不可变性,符合Flutter的不可变设计思想
  2. 工厂函数fromJson:实现单个JSON对象到实体类的解析,对空值做默认处理
  3. 静态方法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,
        );
      },
    );
  }
}

核心要点

  1. initState中调用数据加载方法,保证页面初始化时立即请求数据
  2. 增加加载状态_isLoading,优化用户体验,加载中展示加载圈
  3. 增加异常捕获,数据加载失败时给出Toast提示,避免页面崩溃
  4. 轮播图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));
  },
);

可通过loadingBuildererrorBuilder添加占位图,进一步优化网络图片的加载体验。

三、数据流程图

本次轮播图数据获取的整体流程遵循分层设计,数据流转清晰,各层职责明确,流程图如下:

复制代码
用户进入页面 → 页面初始化调用API → API层调用网络工具类 → Dio发送GET请求 → 接口返回JSON数据
→ 网络工具类处理业务状态码 → API层解析为实体类列表 → 页面层接收数据并更新UI → 轮播图渲染网络图片

各层职责:

  1. 页面层:负责UI展示、用户交互、调用API获取数据
  2. API层:封装接口调用方法,解耦页面与网络请求
  3. 网络工具层:封装Dio,实现通用的网络请求能力
  4. 模型层:实现JSON数据与实体类的解析,规范数据格式
  5. 常量层:统一管理配置参数,避免硬编码

四、项目工程结构

本次开发后,项目的核心工程结构如下(按功能分层),符合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鸿蒙开发中轮播图网络数据获取与展示的完整实现,核心知识点和开发规范总结如下:

  1. 网络请求:使用Dio库实现HTTP请求,通过二次封装提升代码复用性和可维护性
  2. 工程化设计:采用分层开发思想,将页面、API、网络、模型、常量分层管理,解耦各模块逻辑
  3. 数据解析:创建实体类并添加工厂函数,规范JSON数据解析,避免空指针问题
  4. 异常处理:在网络请求、数据解析、页面调用等环节增加异常捕获,保证应用的稳定性
  5. 体验优化:增加加载状态、异常提示、网络图片占位图,提升用户体验
  6. 鸿蒙适配:本次开发的代码可直接在鸿蒙端运行,无需额外修改,符合Flutter跨平台特性

通过本次开发,不仅实现了轮播图的网络数据渲染,还掌握了Flutter工程化开发的核心思想,后续可将此套方案复用至其他业务模块的网络请求开发中。在实际项目中,还可在此基础上扩展请求缓存、token鉴权、多环境配置等功能,进一步提升项目的实用性。


✨ 坚持用 清晰的图解 +易懂的硬件架构 + 硬件解析, 让每个知识点都 简单明了 !

🚀 个人主页一只大侠的侠 · CSDN

💬 座右铭 : "所谓成功就是以自己的方式度过一生。"

相关推荐
sugar_hang5 小时前
Flutter 中的 TCP
flutter
DolitD6 小时前
云流技术深度剖析:国内云渲染主流技术与开源和海外厂商技术实测对比
功能测试·云原生·开源·云计算·实时云渲染
Lionel6896 小时前
鸿蒙Flutter跨平台开发:首页特惠推荐模块的实现
华为·harmonyos
盐焗西兰花6 小时前
鸿蒙学习实战之路-Reader Kit自定义页面背景最佳实践
学习·华为·harmonyos
果粒蹬i6 小时前
【HarmonyOS】DAY10:React Native开发应用品质升级:响应式布局与用户体验优化实践
华为·harmonyos·ux
早點睡3907 小时前
基础入门 React Native 鸿蒙跨平台开发:react-native-flash-message 消息提示三方库适配
react native·react.js·harmonyos
一战成名9967 小时前
深度解析 CANN 模型转换工具链:从 ONNX 到 OM
人工智能·学习·安全·开源
子春一7 小时前
Flutter for OpenHarmony:形状拼图:基于路径几何与空间吸附的交互式拼图系统架构解析
flutter·系统架构
早點睡3908 小时前
高级进阶 ReactNative for Harmony项目鸿蒙化三方库集成实战:react-native-image-picker(打开手机相册)
react native·react.js·harmonyos