架构设计
- 网络请求层
- 职责:负责发起实际的网络请求,处理网络相关的基础操作,如设置请求头、处理HTTP状态码等。使用如
http
或dio
库进行网络请求。
- 示例代码(以
dio
为例):
import 'package:dio/dio.dart';
class NetworkService {
final Dio dio = Dio();
Future<Response> get(String url, {Map<String, dynamic>? queryParameters}) async {
try {
return await dio.get(url, queryParameters: queryParameters);
} catch (e) {
throw NetworkException.fromDioError(e);
}
}
}
- 异常处理层
- 职责:捕获网络请求层抛出的异常,将其转换为自定义的异常类型,并根据异常类型进行分类处理。比如区分网络超时、服务器错误、解析失败等异常。
- 自定义异常类:
class NetworkException implements Exception {
final String message;
final int? statusCode;
NetworkException(this.message, {this.statusCode});
factory NetworkException.fromDioError(DioError error) {
switch (error.type) {
case DioErrorType.connectTimeout:
return NetworkException('网络连接超时', statusCode: error.response?.statusCode);
case DioErrorType.sendTimeout:
return NetworkException('网络发送数据超时', statusCode: error.response?.statusCode);
case DioErrorType.receiveTimeout:
return NetworkException('网络接收数据超时', statusCode: error.response?.statusCode);
case DioErrorType.response:
return NetworkException('服务器错误 ${error.response?.statusCode}', statusCode: error.response?.statusCode);
case DioErrorType.cancel:
return NetworkException('网络请求已取消');
case DioErrorType.other:
return NetworkException('网络其他错误');
}
}
}
- 数据缓存层
- 职责:负责缓存网络请求的数据。可以使用如
shared_preferences
(简单数据缓存)或hive
(更复杂数据结构缓存)。缓存的数据应包含过期时间,以便判断数据是否仍然有效。
- 示例代码(以
shared_preferences
缓存简单字符串数据为例):
import 'package:shared_preferences/shared_preferences.dart';
class CacheService {
static const String cacheKeyPrefix = 'network_cache_';
Future<void> saveCache(String key, String value, {int durationInSeconds = 3600}) async {
final prefs = await SharedPreferences.getInstance();
final cacheData = '$value|${DateTime.now().millisecondsSinceEpoch + durationInSeconds * 1000}';
await prefs.setString('$cacheKeyPrefix$key', cacheData);
}
Future<String?> getCache(String key) async {
final prefs = await SharedPreferences.getInstance();
final cacheData = prefs.getString('$cacheKeyPrefix$key');
if (cacheData == null) return null;
final parts = cacheData.split('|');
final expirationTime = int.parse(parts[1]);
if (DateTime.now().millisecondsSinceEpoch > expirationTime) {
await prefs.remove('$cacheKeyPrefix$key');
return null;
}
return parts[0];
}
}
- UI层
- 职责:向网络请求层发起数据请求,接收异常处理层传递的异常信息并展示友好提示给用户。当发生异常时,尝试从数据缓存层获取缓存数据并展示。
- 示例代码(使用
FutureBuilder
):
import 'package:flutter/material.dart';
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final NetworkService networkService = NetworkService();
final CacheService cacheService = CacheService();
String? data;
String? errorMessage;
@override
void initState() {
super.initState();
_fetchData();
}
Future<void> _fetchData() async {
try {
final response = await networkService.get('https://example.com/api/data');
data = response.data.toString();
await cacheService.saveCache('my_data_key', data!);
} on NetworkException catch (e) {
errorMessage = e.message;
final cachedData = await cacheService.getCache('my_data_key');
if (cachedData != null) {
data = cachedData;
}
}
setState(() {});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('网络请求异常处理'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (errorMessage != null)
Text('错误: $errorMessage'),
if (data != null)
Text('数据: $data'),
],
),
),
);
}
}
交互流程
- 正常流程
- UI层发起网络请求到网络请求层。
- 网络请求层成功获取数据后返回给UI层,UI层更新界面展示数据。同时,数据缓存层将数据进行缓存。
- 异常流程
- UI层发起网络请求到网络请求层。
- 网络请求层发生异常,将异常抛给异常处理层。
- 异常处理层将异常转换为自定义异常类型并返回给UI层。
- UI层收到异常后,展示友好的错误提示给用户。同时,尝试从数据缓存层获取缓存数据,如果有且未过期,则展示缓存数据,保证UI处于可用状态。