【Harmonyos】开源鸿蒙跨平台训练营DAY8:Flutter鸿蒙开发指南获取轮播图数据

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更新

关键要点:

  1. 使用 dio 库进行网络请求
  2. 封装请求工具,统一处理HTTP状态码和业务状态码
  3. 使用 factory 函数实现JSON到对象的转换
  4. API层返回业务层需要的数据结构
  5. 组件支持网络图片加载和错误处理

项目地址: https://atomgit.com/lbbxmx111/haromyos_day_four


参考资料


感谢阅读! 如果本文对你有帮助,请点赞收藏。有问题欢迎评论区交流!

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

📕个人领域 :Linux/C++/java/AI

🚀 个人主页有点流鼻涕 · CSDN

💬 座右铭 : "向光而行,沐光而生。"

相关推荐
2501_944396192 小时前
Flutter for OpenHarmony 视力保护提醒App实战 - 性能优化技巧
android·flutter·性能优化
哈__2 小时前
ReactNative for Harmony 项目鸿蒙化三方库集成实战:react-native-svg
react native·react.js·harmonyos
子春一2 小时前
Flutter for OpenHarmony:构建一个专业级 Flutter 节拍器,深入解析定时器、状态同步与音乐节奏交互设计
javascript·flutter·交互
以太浮标3 小时前
华为eNSP模拟器综合实验之-多协议标签交换 MPLS (Multi-Protocol Label Switching)
华为·智能路由器
kirk_wang3 小时前
Flutter艺术探索-Flutter插件开发:自定义Plugin实战指南
flutter·移动开发·flutter教程·移动开发教程
向哆哆3 小时前
跨端开发实践:Flutter × OpenHarmony 构建垃圾回收分类知识区域
flutter·开源·鸿蒙·openharmony
熊猫钓鱼>_>3 小时前
【开源鸿蒙跨平台开发先锋训练营】Day 9:鸿蒙跨平台Tab 开发问题与列表操作难点复盘
react native·华为·开源·tab·harmonyos·rn·hvigor
kirk_wang3 小时前
Flutter艺术探索-EventChannel使用:原生事件流与Flutter交互
flutter·移动开发·flutter教程·移动开发教程
哈__3 小时前
ReactNative for Harmony 项目鸿蒙化三方库集成实战:react-native-safe-area-context
react native·react.js·harmonyos