1.7. 网络与数据持久化
现代应用几乎都需要网络通信和数据存储能力。
1.7.1. HTTP 网络请求
1.7.1.1. 添加依赖
pubspec.yaml
dependencies:
http: ^1.0.0 # 基础 HTTP 客户端
dio: ^5.0.0 # 功能更丰富的 HTTP 客户端(可选)
1.7.1.2. 基本 GET 请求
import 'dart:convert';
import 'package:http/http.dart' as http;
Future<Map<String, dynamic>> fetchUser(int id) async {
final response = await http.get(
Uri.parse('https://api.example.com/users/$id'),
headers: {'Accept': 'application/json'},
);
if (response.statusCode == 200) {
return json.decode(response.body) as Map<String, dynamic>;
} else {
throw Exception('请求失败: ${response.statusCode}');
}
}
1.7.1.3. POST 请求
Future<Map<String, dynamic>> createUser(String name, String email) async {
final response = await http.post(
Uri.parse('https://api.example.com/users'),
headers: {'Content-Type': 'application/json'},
body: json.encode({
'name': name,
'email': email,
}),
);
if (response.statusCode == 201) {
return json.decode(response.body) as Map<String, dynamic>;
} else {
throw Exception('创建失败: ${response.statusCode}');
}
}
1.7.2. Dio(功能更完善的 HTTP 库)
import 'package:dio/dio.dart';
final dio = Dio(BaseOptions(
baseUrl: 'https://api.example.com',
connectTimeout: const Duration(seconds: 5),
receiveTimeout: const Duration(seconds: 3),
headers: {
'Content-Type': 'application/json',
},
));
// 拦截器(统一处理 Token、日志、错误)
dio.interceptors.add(InterceptorsWrapper(
onRequest: (options, handler) {
options.headers['Authorization'] = 'Bearer $token';
handler.next(options);
},
onResponse: (response, handler) {
handler.next(response);
},
onError: (error, handler) {
handler.next(error);
},
));
// 使用 Dio 请求
Future<User> getUser(int id) async {
final response = await dio.get('/users/$id');
return User.fromJson(response.data);
}
小技巧
Dio 相比 http 的优势:
- 拦截器(统一处理认证、日志、重试)
- 请求取消
- 自动序列化
- 文件上传/下载进度
- 连接超时和重试机制
1.7.3. JSON 序列化
1.7.3.1. 手动序列化
class User {
final int id;
final String name;
final String? email;
const User({
required this.id,
required this.name,
this.email,
});
// JSON → Model
factory User.fromJson(Map<String, dynamic> json) {
return User(
id: json['id'] as int,
name: json['name'] as String,
email: json['email'] as String?,
);
}
// Model → JSON
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
'email': email,
};
}
}
1.7.3.2. 使用 json_serializable(推荐)
添加依赖:
pubspec.yaml
dependencies:
json_annotation: ^4.0.0
dev_dependencies:
json_serializable: ^6.0.0
build_runner: ^2.0.0
定义模型:
import 'package:json_annotation/json_annotation.dart';
part 'user.g.dart'; // 自动生成的文件
@JsonSerializable()
class User {
final int id;
final String name;
@JsonKey(name: 'email_address') // 映射不同名的字段
final String? email;
final DateTime? createdAt;
const User({
required this.id,
required this.name,
this.email,
this.createdAt,
});
factory User.fromJson(Map<String, dynamic> json) =>
_$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}
运行代码生成:
dart run build_runner build # 一次性生成
dart run build_runner watch # 持续监听
小技巧
使用 @JsonKey() 注解处理字段名映射、默认值和忽略字段:
@JsonKey(name: 'full_name', defaultValue: 'anonymous')
1.7.4. 本地数据持久化
1.7.4.2. 文件存储(path_provider)
适合存储文件、日志、图片:
import 'dart:io';
import 'package:path_provider/path_provider.dart';
// 获取应用文档目录
Future<Directory> getDocDir() async {
return await getApplicationDocumentsDirectory();
}
// 写入文件
Future<void> writeFile(String name, String content) async {
final dir = await getDocDir();
final file = File('${dir.path}/$name');
await file.writeAsString(content);
}
// 读取文件
Future<String> readFile(String name) async {
final dir = await getDocDir();
final file = File('${dir.path}/$name');
return await file.readAsString();
}
1.7.4.3. SQLite 数据库(sqflite)
适合存储结构化数据:
pubspec.yaml
dependencies:
sqflite: ^2.0.0
path: ^1.0.0
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
class DatabaseHelper {
static Database? _database;
Future<Database> get database async {
if (_database != null) return _database!;
_database = await _initDatabase();
return _database!;
}
Future<Database> _initDatabase() async {
final path = join(await getDatabasesPath(), 'app.db');
return await openDatabase(
path,
version: 1,
onCreate: (db, version) async {
await db.execute('''
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT
)
''');
},
);
}
Future<int> insertUser(User user) async {
final db = await database;
return await db.insert('users', user.toJson());
}
Future<List<User>> getUsers() async {
final db = await database;
final maps = await db.query('users');
return maps.map((map) => User.fromJson(map)).toList();
}
}
小技巧
对于复杂数据库需求,考虑使用 drift**(原 Moor)或 **ObjectBox, 它们提供了基于类型安全的 ORM。
1.7.5. 网络状态与缓存
import 'dart:io';
import 'package:connectivity_plus/connectivity_plus.dart';
// 检查网络连接
Future<bool> isConnected() async {
try {
final result = await InternetAddress.lookup('google.com');
return result.isNotEmpty && result[0].rawAddress.isNotEmpty;
} on SocketException catch (_) {
return false;
}
}
// 监听网络变化
Connectivity().onConnectivityChanged.listen((result) {
// 处理网络状态变化
});
参见
缓存策略:结合
dio_cache_interceptor实现离线缓存状态同步:结合
Riverpod或Bloc管理异步数据加载状态本地数据库:drift (类型安全)、ObjectBox (高性能)、Hive (轻量级)