Flutter 网络请求框架封装详解
网络请求是移动应用中常用的功能,Flutter提供了丰富的网络请求支持和第三方库,如http、dio等。为了简化开发流程,最好将网络请求进行封装。
封装思路
封装网络请求的主要思路是将网络请求的参数进行封装,提高代码复用率和可读性。一般封装网络请求都会包含以下几个步骤:
- 封装请求参数和请求路径
- 封装请求头
- 封装请求体
- 封装响应数据处理
- 封装异常处理
在封装网络请求时,我们可以使用 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技术站