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

一、前置准备

1.1 步骤

(1)安装 dio
(2)定义常量数据、基础地址、超时时间、业务状态、请求地址
(3)封装网络请求工具,基础地址,拦截器
(4)请求工具进一步解构,处理 http 状态和业务状态
(5)类工厂转化动态类型到对象类型
(6)封装请求 API 调用工厂函数
(7)初始化数据更新状态

1.2 接口请求成功示例

接口基础地址:https://meikou-api.itheima.net

轮播图地址(get):https://meikou-api.itheima.net/home/banner

请求轮播图成功返回的数据:

1.3 dio使用方法

Dart 复制代码
flutter pub add dio

二、轮播图API请求实现

2.1 编写常量类

首先先修改文件夹的名字,因为我之前写错了,这个文件夹用于放置常量。

lib/constants/index.dart代码

为什么要用static修饰?因为:

(1)非静态每个实例都会创建新的内存。

(2)可以全局访问,无需创建对象。

(3)这些配置在应用生命周期内不会改变。

Dart 复制代码
//全局状态
class GlobalConstants {
  //基础地址
  static String BASE_URL = "https://meikou-api.itheima.net/";

  //超时时间
  static int TIME_OUT = 10;

  //成功状态
  static String SUCCESS_CODE = "1";
}

但是以上代码叫作变量,而我们是不需要改变的,所以加上"const"关键字,变为常量

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";
}

完整代码:

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";
}

2.2 封装请求类

在lib/utils文件夹下新建一个DioRequest.dart进行Dio网络请求的封装。

DioRequest.dart代码

Dart 复制代码
//基于Dio进行二次封装
import 'package:dio/dio.dart';
import 'package:qing_mall/constants/index.dart';

class DioRequest {
  final _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状态码 200 300
      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;
    }
  }

  //进一步处理返回结果的函数
  Future<dynamic> _handleResponse(Response<dynamic> task) async {
    try {
      Response<dynamic> res = await task;
      final data = res.data as Map<String, dynamic>; //data才是我们真实的接口返回的数据
      if (data["code"] == GlobalConstants.SUCCESS_CODE) {
        //如果等于1 才认定http状态和业务状态均为正常 就可以正常的放行通过
        return data["result"]; //只要result结果
      }
      //抛出异常
      throw Exception(data["message"] ?? "加载数据异常");
    } catch (e) {
      throw Exception(e);
    }
  }
}

// 单例对象
final dioRequest = DioRequest();

//dio请求工具发出请求->返回的数据通过Response<dynamic>.data
//把所有的接口的data解放出来 拿到真正的数据 要判断业务状态码是不是等于1

2.3 转换动态类型

修改lib/viewmodels/home.dart代码

home.dart代码

Dart 复制代码
class BannerItem {
  String id;
  String imgUrl;

  BannerItem({required this.id, required this.imgUrl});

  //扩展一个工厂函数 一般用factory来声明 一般用来创建实例对象
  factory BannerItem.formJSON(Map<String, dynamic> json) {
    //必须返回一个BannerItem对象
    return BannerItem(id: json["id"] ?? "", imgUrl: json["imgUrl"] ?? "");
  }
}

//每一个轮播图具体类型

//flutter必须强制转换,没有隐式转化

2.4 封装API

在lib/api/目录下新建home.dart,目的是返回业务所需要的数据结构。

完整代码:

Dart 复制代码
//封装一个api 目的是返回业务侧要的数据结构
import 'package:qing_mall/constants/index.dart';
import 'package:qing_mall/utils/DioRequest.dart';
import 'package:qing_mall/viewmodels/home.dart';

Future<List<BannerItem>> getBannerListAPI() async {
  //返回请求
  final tt =
      ((await dioRequest.get(HttpConstants.BANNER_LIST)) as List).map((item) {
    return BannerItem.formJSON(item as Map<String, dynamic>);
  }).toList();
  return tt;
}

修改lib/pages/Home/index.dart代码

完整代码:

Dart 复制代码
import 'package:flutter/cupertino.dart';
import 'package:qing_mall/api/home.dart';
import 'package:qing_mall/components/Home/HmCategory.dart';
import 'package:qing_mall/components/Home/HmHot.dart';
import 'package:qing_mall/components/Home/HmMoreList.dart';
import 'package:qing_mall/components/Home/HmSlider.dart';
import 'package:qing_mall/components/Home/HmSuggestion.dart';
import 'package:qing_mall/viewmodels/home.dart';

class HomeView extends StatefulWidget {
  const HomeView({super.key});

  @override
  State<HomeView> createState() => _HomeViewState();
}

class _HomeViewState extends State<HomeView> {
  List<BannerItem> _bannerList = [
    // BannerItem(
    //   id: "1",
    //   imgUrl: "https://yjy-teach-oss.oss-cn-beijing.aliyuncs.com/meituan/1.jpg",
    // ),
    // BannerItem(
    //   id: "2",
    //   imgUrl: "https://yjy-teach-oss.oss-cn-beijing.aliyuncs.com/meituan/2.png",
    // ),
    // BannerItem(
    //   id: "3",
    //   imgUrl: "https://yjy-teach-oss.oss-cn-beijing.aliyuncs.com/meituan/3.jpg",
    // ),
  ];

  //获取滚动容器的内容

  List<Widget> _getScrollChildren() {
    return [
      //包裹普通widget的sliver家族的组件内容
      SliverToBoxAdapter(child: HmSlider(bannerList: _bannerList)), //轮播图组件
      //放置分类组件
      SliverToBoxAdapter(child: SizedBox(height: 10)),
      //SliverGrid SliverList指南纵向排列
      SliverToBoxAdapter(child: HmCategory()), //分类组件
      SliverToBoxAdapter(child: SizedBox(height: 10)),
      SliverToBoxAdapter(child: HmSuggestion()), //推荐组件
      SliverToBoxAdapter(child: SizedBox(height: 10)),

      //Flex和Expanded配合起来可以均分比例
      SliverToBoxAdapter(
        child: Padding(
            padding: EdgeInsets.symmetric(horizontal: 10),
            child: Flex(
              direction: Axis.horizontal,
              children: [
                Expanded(child: HmHot()),
                SizedBox(
                  width: 10,
                ),
                Expanded(child: HmHot()),
              ],
            )),
      ),
      SliverToBoxAdapter(child: SizedBox(height: 10)),
      HmMorelist(), //无限滚动列表
    ];
  }

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _getBannederList();
  }

  void _getBannederList() async {
    _bannerList = await getBannerListAPI();
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    //CustomScrollview要求:必须是sliver家族的内容
    return CustomScrollView(slivers: _getScrollChildren());
  }
}

以上步骤全部完成后,运行鸿蒙的模拟器,会得到如图所示效果,请求了真实的API接口

三、提交代码

3.1 git可视化提交代码

最后,别忘了提交代码哦。这次我们改用Android Studio的可视化进行git的提交。

选中该图标,如果没有,可能是已经没有装git的插件。

3.2 总结

感谢大家的观看,本项目的地址是:https://AtomGit.com/Deng666/shangcheng.git。如果在文章中复刻遇到问题,可到代码托管仓库克隆一份源码。如果本篇文章对你有帮助,请你点个赞吧!~

最后,欢迎加入开源鸿蒙跨平台社区:

https://openharmonycrossplatform.csdn.net

相关推荐
梦想的颜色4 小时前
【编程实战】AI 时代 APP 开发全栈硬核指南:技术选型 + AI 架构 + 模型落地全维度决策
python·flutter·react native·react.js·ai·桌面应用·milvus
yuanlaile1 天前
2026年全新Flutter 跨平台开发全栈学习资料整理
flutter·getx·鸿蒙 next·flutter开发鸿蒙·flutter入门实战·flutter全栈
恋猫de小郭1 天前
Genkit Dart 1.0 发布,Flutter 原生的 AI Agent 终于完整了
android·前端·flutter
第10086个小白1 天前
flutter桌面端打包方式(Inno Setup Compiler)版本
前端·flutter
陆断枫2 天前
Flutter 3.47 动画引擎盘点:Impeller 全平台,和那些"新特性"
flutter
程序员老刘2 天前
Flet 1.0 思路很好,可惜来晚了
flutter·ai编程·客户端
m0_738185822 天前
Flutter 鸿蒙化实战:qr_code_scanner_plus 适配 OpenHarmony,二维码扫描
flutter·华为·harmonyos·鸿蒙
恋猫de小郭2 天前
Flutter + EmbeddingGemma 2,谷歌发布完全端侧的 AI Edge Foresight
android·前端·flutter
君赏3 天前
基于 FlutterPatch 快速接入 Flutter 热更新
flutter
律宏阔3 天前
Dart FFI 内存管理:用 using + Arena 替代嵌套 try-finally
前端·flutter