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

相关推荐
晚霞的不甘2 小时前
Flutter for OpenHarmony《智慧字典》英语学习模块代码深度解析:从数据模型到交互体验
前端·学习·flutter·搜索引擎·前端框架·交互
子春一2 小时前
Flutter for OpenHarmony:构建一个优雅的 Flutter 每日一句应用,深入解析状态管理、日期驱动内容与 Material 3 交互动效
javascript·flutter·交互
菜鸟小芯2 小时前
【开源鸿蒙跨平台开发先锋训练营】DAY8~DAY13 底部选项卡&美食功能实现
flutter·harmonyos
子春一2 小时前
Flutter for OpenHarmony:构建一个沉浸式 Flutter 掷骰子游戏,深入解析动画控制器、CustomPaint 自定义绘制与状态同步
flutter·游戏
程序员清洒10 小时前
Flutter for OpenHarmony:GridView — 网格布局实现
android·前端·学习·flutter·华为
嘴贱欠吻!11 小时前
Flutter鸿蒙开发指南(七):轮播图搜索框和导航栏
算法·flutter·图搜索算法
Miguo94well11 小时前
Flutter框架跨平台鸿蒙开发——地理知识速记APP的开发流程
flutter·华为·harmonyos·鸿蒙
LawrenceLan11 小时前
Flutter 零基础入门(二十六):StatefulWidget 与状态更新 setState
开发语言·前端·flutter·dart
2401_8920005212 小时前
Flutter for OpenHarmony 猫咪管家App实战 - 添加提醒实现
前端·javascript·flutter