Flutter 網絡請求與數據處理:從基礎到單例封裝
在 Flutter 開發中,網絡請求是一個非常常見的需求,比如獲取 API 數據、上傳文件、處理分頁加載等。為了高效地處理網絡請求和數據管理,我們需要選擇合適的工具并進行合理的封裝。
本篇博客將詳細介紹 Flutter 中網絡請求的基礎知識、常用庫(如 http
和 dio
),并最終實現一個單例模式的網絡請求封裝,幫助你在項目中高效管理網絡請求。
1. 網絡請求的基礎知識
1.1 HTTP 請求的基本類型
- GET:從服務器獲取數據。
- POST:向服務器發送數據。
- PUT:更新服務器上的數據。
- DELETE:刪除服務器上的數據。
1.2 常用的網絡請求庫
http
:- Flutter 官方提供的輕量級 HTTP 客戶端。
- 適合簡單的網絡請求。
dio
:- 功能強大的第三方庫,支持攔截器、文件上傳下載、請求取消等。
- 適合復雜的網絡請求場景。
2. 使用 http
進行網絡請求
2.1 安裝 http
在 pubspec.yaml
中添加依賴:
dependencies:http: ^0.15.0
運行以下命令安裝依賴:
flutter pub get
2.2 基本用法
GET 請求
import 'dart:convert';
import 'package:http/http.dart' as http;void fetchData() async {final url = Uri.parse("https://jsonplaceholder.typicode.com/posts");final response = await http.get(url);if (response.statusCode == 200) {final data = json.decode(response.body);print("數據加載成功:$data");} else {print("請求失敗,狀態碼:${response.statusCode}");}
}void main() {fetchData();
}
POST 請求
void postData() async {final url = Uri.parse("https://jsonplaceholder.typicode.com/posts");final response = await http.post(url,headers: {"Content-Type": "application/json"},body: json.encode({"title": "Flutter", "body": "Hello World", "userId": 1}),);if (response.statusCode == 201) {final data = json.decode(response.body);print("數據提交成功:$data");} else {print("請求失敗,狀態碼:${response.statusCode}");}
}void main() {postData();
}
3. 使用 dio
進行網絡請求
3.1 安裝 dio
在 pubspec.yaml
中添加依賴:
dependencies:dio: ^5.0.0
運行以下命令安裝依賴:
flutter pub get
3.2 基本用法
GET 請求
import 'package:dio/dio.dart';void fetchData() async {final dio = Dio();final response = await dio.get("https://jsonplaceholder.typicode.com/posts");if (response.statusCode == 200) {print("數據加載成功:${response.data}");} else {print("請求失敗,狀態碼:${response.statusCode}");}
}void main() {fetchData();
}
POST 請求
void postData() async {final dio = Dio();final response = await dio.post("https://jsonplaceholder.typicode.com/posts",data: {"title": "Flutter", "body": "Hello World", "userId": 1},);if (response.statusCode == 201) {print("數據提交成功:${response.data}");} else {print("請求失敗,狀態碼:${response.statusCode}");}
}void main() {postData();
}
3.3 使用攔截器
dio
提供了強大的攔截器功能,可以在請求前后進行統一處理。
示例:添加攔截器
void fetchDataWithInterceptor() async {final dio = Dio();// 添加攔截器dio.interceptors.add(InterceptorsWrapper(onRequest: (options, handler) {print("請求開始:${options.uri}");return handler.next(options);},onResponse: (response, handler) {print("請求成功:${response.data}");return handler.next(response);},onError: (error, handler) {print("請求失敗:${error.message}");return handler.next(error);},));final response = await dio.get("https://jsonplaceholder.typicode.com/posts");print(response.data);
}void main() {fetchDataWithInterceptor();
}
4. 單例模式封裝網絡請求
在實際項目中,網絡請求通常需要統一管理,比如設置基礎 URL、添加攔截器、處理錯誤等。通過單例模式封裝網絡請求,可以提高代碼的復用性和可維護性。
4.1 單例封裝 dio
封裝代碼
import 'package:dio/dio.dart';class DioClient {// 單例模式static final DioClient _instance = DioClient._internal();factory DioClient() => _instance;late Dio _dio;DioClient._internal() {_dio = Dio(BaseOptions(baseUrl: "https://jsonplaceholder.typicode.com",connectTimeout: const Duration(seconds: 10),receiveTimeout: const Duration(seconds: 10),headers: {"Content-Type": "application/json"},));// 添加攔截器_dio.interceptors.add(InterceptorsWrapper(onRequest: (options, handler) {print("請求開始:${options.uri}");return handler.next(options);},onResponse: (response, handler) {print("請求成功:${response.data}");return handler.next(response);},onError: (error, handler) {print("請求失敗:${error.message}");return handler.next(error);},));}// GET 請求Future<Response> get(String path, {Map<String, dynamic>? queryParameters}) async {return await _dio.get(path, queryParameters: queryParameters);}// POST 請求Future<Response> post(String path, {Map<String, dynamic>? data}) async {return await _dio.post(path, data: data);}// PUT 請求Future<Response> put(String path, {Map<String, dynamic>? data}) async {return await _dio.put(path, data: data);}// DELETE 請求Future<Response> delete(String path, {Map<String, dynamic>? data}) async {return await _dio.delete(path, data: data);}
}
4.2 使用封裝的 DioClient
GET 請求
void fetchData() async {final dioClient = DioClient();final response = await dioClient.get("/posts");if (response.statusCode == 200) {print("數據加載成功:${response.data}");} else {print("請求失敗,狀態碼:${response.statusCode}");}
}void main() {fetchData();
}
POST 請求
void postData() async {final dioClient = DioClient();final response = await dioClient.post("/posts",data: {"title": "Flutter", "body": "Hello World", "userId": 1},);if (response.statusCode == 201) {print("數據提交成功:${response.data}");} else {print("請求失敗,狀態碼:${response.statusCode}");}
}void main() {postData();
}
5. 總結
5.1 http
和 dio
的對比
特性 | http | dio |
---|---|---|
功能 | 輕量級,適合簡單請求 | 功能強大,支持攔截器、文件上傳等 |
學習曲線 | 低 | 中 |
擴展性 | 較低 | 高 |
適用場景 | 小型項目 | 中型和大型項目 |
5.2 實踐建議
- 小型項目:
- 使用
http
,簡單易用。
- 使用
- 中型和大型項目:
- 使用
dio
,并通過單例模式封裝,統一管理網絡請求。
- 使用