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日

相关文章

  • iOS13.2开发者预览版beta1更新了什么 更新内容及升级方法(附全机型固件及描述文件下载

    iOS 13.2开发者预览版beta1更新内容及升级方法攻略 更新内容 iOS 13.2开发者预览版beta1已经发布,其中包含了以下更新内容: Deep Fusion摄影技术:适用于iPhone 11、iPhone 11 Pro和iPhone 11 Pro Max的新摄影技术,可提供更出色的细节和更低的噪音水平。 支持AirPods Pro:可定制的降噪功…

    other 2023年6月26日
    00
  • Android studio升级4.1时遇到的问题记录

    Android Studio升级4.1问题记录攻略 问题1:无法启动Android Studio 4.1 描述: 在升级Android Studio到4.1版本后,尝试启动应用程序时遇到了问题。应用程序无法正常启动,出现错误提示。 解决方案: 确保已经关闭Android Studio。 打开项目文件夹,找到并删除以下文件夹: .idea:包含项目的配置信息。…

    other 2023年8月20日
    00
  • windows10redis部署

    Windows 10下Redis的部署 Redis是一个高性能的键值对数据库,常用于缓存、消息队列等场景。在Windows 10操作系统下,Redis的部署相对于其他操作系统可能需要更多的配置和调整。本文将介绍如何在Windows 10下部署Redis。 1. 安装Redis 首先,需要到Redis官网下载最新的Windows版本,下载地址为 https:/…

    其他 2023年3月28日
    00
  • Sqlmap爆库命令的简单使用

    作为一款流行的Java Web开发框架,Spring Boot提供了许多有用的注解来简化开发过程。其中,@Cacheable注解可以用于实现缓存功能,提高应用程序的性能和响应速度。本文将详细讲解@Cacheable注解的作用和使用方法,并提供两个示例说明。 作用 @Cacheable注解的作用是将一个方法的返回值缓存起来,以便在下次调用该方法时可以直接从缓存…

    other 2023年5月5日
    00
  • Windows10环境安装sdk8的图文教程

    下面是详细的Windows10环境安装sdk8的图文教程: 准备工作 在进行安装之前,需要先进行一些准备工作: 确保电脑已经安装了JDK,并且环境变量配置正确。 下载适用于Windows的jdk-8uXXX-windows-x64.exe安装文件,XXX表示版本号。 安装过程 双击jdk-8uXXX-windows-x64.exe安装文件,弹出安装向导,点击…

    other 2023年6月27日
    00
  • C++常用字符串函数大全(2)

    C++常用字符串函数大全(2) 本文为C++字符串函数系列文章的第2篇,主要介绍C++标准库中常用的字符串函数,包括: strncpy(): 复制n个字符到目标字符串中。 strncat(): 将目标字符串和n个字符的源字符串拼接到一起。 strstr(): 在字符串中查找子串。 strspn(): 返回目标字符串开头连续包含源字符串字符的数目。 strcs…

    other 2023年6月20日
    00
  • jq中的事件委托:closest parent parents delegate

    jq中的事件委托: closest parent parents delegate jQuery是一种流行的JavaScript库,简化了处理HTML文档、处理元素的方法和事件,其中事件委托是一个非常重要的概念。事件委托可以提高代码的性能,减少内存消耗,同时还可以处理动态创建的元素。jQuery提供了closest、parent、parents、delega…

    其他 2023年3月28日
    00
  • AngularJs Scope详解及示例代码

    AngularJS中的Scope是一个JavaScript对象,它是AngualrJS的重要特性之一,负责管理数据和事件。在AngularJS中,Scope扮演了“模型”的角色,通过双向数据绑定实现了页面数据与Model数据的同步。 下面我们来详细讲解一下AngularJS中的Scope。 Scope的作用 在AngularJS中,Scope主要有以下两个作…

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