Flutter 网络请求框架封装详解

Flutter 网络请求框架封装详解

网络请求是移动应用中常用的功能,Flutter提供了丰富的网络请求支持和第三方库,如http、dio等。为了简化开发流程,最好将网络请求进行封装。

封装思路

封装网络请求的主要思路是将网络请求的参数进行封装,提高代码复用率和可读性。一般封装网络请求都会包含以下几个步骤:

  1. 封装请求参数和请求路径
  2. 封装请求头
  3. 封装请求体
  4. 封装响应数据处理
  5. 封装异常处理

在封装网络请求时,我们可以使用 Flutter 或第三方库提供的网络请求 API。下面介绍如何使用 dio 封装网络请求。

使用dio封装网络请求

dio 是一个强大的 Darts/Flutter Http 客户端,支持 Restful API、FormData、拦截器、请求取消、Cookie 管理、文件上传/download、超时等功能。在使用 dio 之前,需要在项目的 pubspec.yaml 文件中引入 dio 包。

dependencies:
  dio: ^4.0.0

对于一个网络请求工具类而言,一般需要满足以下几个要求:

  • 代码需要易于维护和扩展
  • 方便我们自定义请求头和拦截器
  • 方便我们统一处理网络请求的异常
  • 支持多种请求方法,如 GET、POST 等
  • 支持请求参数和请求体的封装
  • 支持请求的超时设置
  • 支持文件上传和下载

下面是一个利用 dio 封装网络请求的示例代码,供参考:

import 'package:dio/dio.dart';

class HttpUtil {
  static Dio _dio =
      Dio(BaseOptions(baseUrl: "https://www.xxxx.com", connectTimeout: 5000));

  static Future<dynamic> get(String url,
      {Map<String, dynamic>? queryParameters,
      Options? options}) async {
    Response<dynamic> response;

    try {
      response = await _dio.get(url,
          queryParameters: queryParameters, options: options);
    } on DioError catch (e) {
      _handleError(e);
    }

    return response;
  }

  static Future<dynamic> post(String url,
      {Map<String, dynamic>? queryParameters,
      dynamic data,
      Options? options}) async {
    Response<dynamic> response;

    try {
      response = await _dio.post(url,
          queryParameters: queryParameters, data: data, options: options);
    } on DioError catch (e) {
      _handleError(e);
    }

    return response;
  }

  static void _handleError(DioError e) {
    switch (e.type) {
      case DioErrorType.cancel:
        print("请求已被取消");
        break;
      case DioErrorType.connectTimeout:
        print("连接超时");
        break;
      case DioErrorType.sendTimeout:
        print("请求超时");
        break;
      case DioErrorType.receiveTimeout:
        print("响应超时");
        break;
      case DioErrorType.response:
        print("HTTP 响应异常");
        break;
      case DioErrorType.other:
        print("其它异常");
        break;
      default:
        print("网络异常");
    }
  }
}

在这个示例中,我们利用了 dio 的 BaseOptions 控制超时时间,也使用了 DioError 类型来处理请求异常。同时也支持了 Get 和 Post 等请求方式,支持传入请求参数 Map 和数据体。

示范应用示例

接下来我们将提供两个在 Flutter 中使用网络请求的示范代码示例。

示例1:异步请求天气API

在这个示例中,我们将创建一个简单的天气 API 请求的程序。在这个示例中,我们使用了 http 包和 JSON 解析器 convert 包来获取环球时报的天气 API。

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String _data = "";

  Future<String> _getWeather() async {
    var url = Uri.parse(
        'http://weatherapi.market.xiaomi.com/wtr-v2/weather?cityId=101020100');
    var response = await http.get(url);
    Map<String, dynamic> weatherMap = json.decode(response.body);
    return weatherMap.toString();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Weather API'),
        ),
        body: Center(
          child: ElevatedButton(
            onPressed: () async {
              String data = await _getWeather();
              setState(() {
                _data = data;
              });
            },
            child: const Text('Get Weather'),
          ),
        ),
      ),
    );
  }
}

在这个示例中,我们创建了一个 MyApp 组件,它有一个有名的 _getWeather() 方法,用来获取 API 返回的天气数据。然后在页面中创建了一个包含 “Get Weather” 文字的 ElevatedButton,用来触发事件,进而刷新页面。

在方法中,我们定义了一个名字为 url 的变量,接着把这个变量转换成 Uri 对象。然后我们使用 HTTP 包中的 http.get 方法请求 API,并且使用 JSON 包解析返回的结果。最后这个方法会输出三天内的天气条件和气温。

示例2:待完成任务列表的更新任务

在这个示例中,我们将创建一个任务列表,用户可以添加任务并将任务标记为已完成。这个任务列表通过 HTTP 请求和 JSON API 来支持在多个设备上同步任务列表。

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  List<String> tasks = [];

  Future _getTasks() async {
    var url = Uri.parse('https://api.example.com/tasks');
    var response = await http.get(url);

    Map<String, dynamic> data = json.decode(response.body);

    List<String> newTasks = [];

    for (var taskJson in data['tasks']) {
      newTasks.add(taskJson['title']);
    }

    setState(() {
      tasks = newTasks;
    });
  }

  Future _addTask(String task) async {
    var url = Uri.parse('https://api.example.com/task');

    await http.post(url, body: {'title': task});

    await _getTasks();
  }

  Future _toggleTask(String task) async {
    var url = Uri.parse('https://api.example.com/task/$task');
    var response = await http.put(url);

    await _getTasks();
  }

  @override
  void initState() {
    super.initState();

    _getTasks();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Task List'),
        ),
        body: Column(
          children: [
            Expanded(
              child: ListView.builder(
                itemCount: tasks.length,
                itemBuilder: (context, index) {
                  var task = tasks[index];

                  return ListTile(
                    title: Text(task),
                    trailing: Checkbox(
                      value: false,
                      onChanged: (bool? value) {
                        _toggleTask(task);
                      },
                    ),
                  );
                },
              ),
            ),
            Padding(
              padding: const EdgeInsets.all(16.0),
              child: TextField(
                decoration: InputDecoration(hintText: 'Add a task'),
                onSubmitted: (text) {
                  _addTask(text);
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}

在这个示例中,我们创建了一个 MyApp 组件,它包含了一个包含数据抽象的 tasks 列表属性,它使用 HTTP 包和JSON解析器 convert 包来获取环球任务。

在页面中,我们创建了一个任务列表视图,用 ListTile 表示每个任务。点击每项任务右侧的 Checkbox 可以加入或取消完成状态。在最底部的文本框中输入新任务,按下回车键可以添加新任务。

当其中一个列表项被点击时,它将在底层调用 _toggleTask 方法。这个方法通过 HTTP PUT 请求把任务标记为已完成,并调用了 _getTasks 拉取最新的任务数据。在添加新任务时,我们将在底部文本输入框上启动方法,该方法将使用 POST 请求将新任务提交到 API,然后在在底层调用 _getTasks 方法拉取最新的任务数据。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Flutter 网络请求框架封装详解 - Python技术站

(0)
上一篇 2023年6月25日
下一篇 2023年6月25日

相关文章

  • win11电脑定时重启怎么设置? Win11设置定时重启的技巧

    下面是关于win11电脑定时重启的设置攻略。 1. Win11设置定时重启的方法 Win11系统也可以设置电脑的定时重启,方法如下: 步骤1:打开开始菜单 首先,点击左下角的“开始”按钮,将开始菜单打开。 步骤2:进入设置 打开开始菜单后,找到并点击“设置”图标,进入设置页面。 步骤3:选择“更新和安全” 在设置页面中,选择“更新和安全”选项,进入“更新和安…

    other 2023年6月27日
    00
  • python根据完整路径获得盘名/路径名/文件名/文件扩展名的方法

    Python提供了os模块来处理文件和目录的操作。下面我将介绍如何使用os模块来根据完整路径获得盘名/路径名/文件名/文件扩展名。以下是具体解释: 获取盘名 通过os.path.splitdrive()函数来获取路径的盘符。 import os path = ‘C:/Users/Administrator/Desktop/test.txt’ drive, p…

    other 2023年6月26日
    00
  • 详解Android TabHost的多种实现方法 附源码下载

    详解Android TabHost的多种实现方法 附源码下载 简介 Android TabHost是一个用于实现选项卡界面的控件,可以在一个界面中显示多个选项卡,并通过切换选项卡来显示不同的内容。本攻略将详细介绍Android TabHost的多种实现方法,并提供源码下载。 方法一:使用TabHost和TabWidget 首先,在XML布局文件中定义TabH…

    other 2023年9月7日
    00
  • 指定端口号的scp

    指定端口号的SCP攻略 SCP(Secure Copy)是一种基于SSH协议的文件传输工具,用于在本地计算机和远程计算机之间传文件。在使用时,可以通过指定端口号来连接远程计算机。本攻略将详细讲解如何指定端口号的,包括SCP的基本概念、如何指定端口号、以及两个示例说明。 SCP的基本概念 SCP是一种基于SSH协议的文件传输工具,用于在本地计算机和远程计算机之…

    other 2023年5月7日
    00
  • 新安装的XAMPP访问phpmyadmin出错的解决方法

    如果你新安装的XAMPP出现了访问phpmyadmin出错的问题,一般有以下两种可能的解决方法: 方法一:重启Apache和MySQL服务 有时候出错的原因可能是因为Apache和MySQL服务没有正常启动,所以你可以尝试通过重启这两个服务来解决此问题。具体步骤如下: 在XAMPP控制面板中,停止Apache和MySQL服务 点击“Start”按钮,再次启动…

    other 2023年6月26日
    00
  • Python扩展内置类型详解

    Python扩展内置类型详解攻略 什么是Python扩展内置类型? Python扩展内置类型指的是Python中内置的原生类型,比如list或dict等,这些类型在Python中是非常常用的,并且可以被扩展和定制以适应不同的需求。 如何扩展内置类型? 要扩展内置类型,可以使用Python的类继承机制或者定义一批C语言函数。在这里我们主要介绍使用类继承机制,通…

    other 2023年6月26日
    00
  • 在std::thread中创建并管理QEventLoop的全面解析

    在std::thread中创建并管理QEventLoop的目的是为了在一个线程中实现Qt框架的GUI和非GUI程序。该过程可以通过以下步骤来实现: 1. 创建一个std::thread对象 首先,我们需要使用std::thread的构造函数创建一个std::thread对象。该构造函数接受一个函数指针或lambda表达式作为参数,该函数或lambda表达式将…

    other 2023年6月27日
    00
  • java非递归实现之二叉树的前中后序遍历详解

    Java非递归实现之二叉树的前中后序遍历详解 1、概述 在程序设计中,二叉树是一种常用的数据结构,而对二叉树进行遍历则是非常基础和重要的操作。二叉树的遍历分为三种:前序遍历、中序遍历和后序遍历。 常规的二叉树遍历算法使用递归完成,但是递归算法的效率比较低,同时深度过深还会导致调用栈溢出,因此我们可以采用非递归的方式来实现二叉树的遍历。 本文将通过Java代码…

    other 2023年6月27日
    00
合作推广
合作推广
分享本页
返回顶部