导语
在 Flutter 开发中,本地数据持久化是核心需求之一。选择合适的存储方案并遵循最佳实践,不仅能提升应用性能,还能增强代码的可维护性和可测试性。本文系统对比 SharedPreferences、Hive 和 SQLite 三种主流存储方案,从基础封装到架构设计,带你构建健壮的本地存储系统。
一、SharedPreferences:轻量级键值存储优化
SharedPreferences 适合存储简单的键值对数据(如用户配置、Token 等),以下是企业级封装方案:
dart
// lib/core/storage/shared_preferences_service.dart
import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter/foundation.dart';
/// 轻量级键值存储服务
/// 适用于:用户偏好设置、认证Token、简单配置项
class SharedPreferencesService {
static SharedPreferences? _instance;
static bool _isInitialized = false;
/// 初始化服务(建议在main函数中调用)
static Future<void> initialize() async {
if (!_isInitialized) {
_instance = await SharedPreferences.getInstance();
_isInitialized = true;
}
}
/// 获取实例(确保已初始化)
static SharedPreferences get instance {
assert(_isInitialized, 'SharedPreferencesService未初始化,请先调用initialize()');
return _instance!;
}
// MARK: - 通用操作方法
static Future<bool> setValue<T>(String key, T value) async {
try {
switch (T) {
case String:
return await instance.setString(key, value as String);
case int:
return await instance.setInt(key, value as int);
case bool:
return await instance.setBool(key, value as bool);
case double:
return await instance.setDouble(key, value as double);
case List<String>:
return await instance.setStringList(key, value as List<String>);
default:
throw UnsupportedError('不支持的类型: ${T.runtimeType}');
}
} catch (e) {
debugPrint('SharedPreferences存储失败: $key - $e');
return false;
}
}
static T? getValue<T>(String key, {T? defaultValue}) {
try {
switch (T) {
case String:
return instance.getString(key) as T? ?? defaultValue;
case int:
return instance.getInt(key) as T? ?? defaultValue;
case bool:
return instance.getBool(key) as T? ?? defaultValue;
case double:
return instance.getDouble(key) as T? ?? defaultValue;
case List<String>:
return instance.getStringList(key) as T? ?? defaultValue;
default:
return defaultValue;
}
} catch (e) {
debugPrint('SharedPreferences读取失败: $key - $e');
return defaultValue;
}
}
// MARK: - 便捷方法
static Future<bool> remove(String key) async => await instance.remove(key);
static Future<bool> clear() async => await instance.clear();
static bool containsKey(String key) => instance.containsKey(key);
// MARK: - 类型安全的命名键
static const String kAuthToken = 'auth_token';
static const String kThemeMode = 'theme_mode';
static const String kFirstLaunch = 'first_launch';
}
使用示例:
dart
// main.dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// 初始化存储服务
await SharedPreferencesService.initialize();
// 安全存储Token
await SharedPreferencesService.setValue(
SharedPreferencesService.kAuthToken,
'your_jwt_token_here'
);
// 读取Token
final token = SharedPreferencesService.getValue<String>(
SharedPreferencesService.kAuthToken
);
runApp(const MyApp());
}
二、Hive:高性能 NoSQL 存储方案
Hive 适合存储复杂对象和本地缓存,以下是分层架构的实现方案:
1. 实体模型设计
dart
// lib/features/notes/data/models/note_model.dart
import 'package:hive/hive.dart';
import 'package:equatable/equatable.dart';
part 'note_model.g.dart';
/// 笔记数据模型
/// Hive TypeId: 0
@HiveType(typeId: 0)
class NoteModel extends HiveObject with EquatableMixin {
@HiveField(0)
final String id;
@HiveField(1)
String title;
@HiveField(2)
String content;
@HiveField(3)
final DateTime createdAt;
@HiveField(4)
DateTime updatedAt;
@HiveField(5)
final List<String> tags;
NoteModel({
required this.id,
required this.title,
required this.content,
required this.createdAt,
required this.updatedAt,
this.tags = const [],
});
// 更新笔记
NoteModel copyWith({
String? title,
String? content,
DateTime? updatedAt,
List<String>? tags,
}) {
return NoteModel(
id: id,
title: title ?? this.title,
content: content ?? this.content,
createdAt: createdAt,
updatedAt: updatedAt ?? DateTime.now(),
tags: tags ?? this.tags,
);
}
@override
List<Object?> get props => [id, title, content, createdAt, updatedAt, tags];
}
2. Hive 服务封装
dart
// lib/core/storage/hive_service.dart
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:flutter/foundation.dart';
/// Hive存储服务
/// 负责初始化、配置和提供Box实例
class HiveService {
static const String kEncryptionKey = 'your_secure_encryption_key'; // 实际项目中使用安全方式存储
/// 初始化Hive
static Future<void> initialize() async {
await Hive.initFlutter();
// 注册适配器(代码生成)
_registerAdapters();
// 打开常用Box(可配置加密)
await _openBoxes();
}
/// 注册所有Hive对象适配器
static void _registerAdapters() {
Hive.registerAdapter(NoteModelAdapter());
// 注册其他适配器...
}
/// 打开应用所需的Box
static Future<void> _openBoxes() async {
// 示例:加密Box
// final encryptionKey = Hive.generateSecureKey();
// await Hive.openBox<NoteModel>('notes', encryptionCipher: HiveAesCipher(encryptionKey));
await Hive.openBox<NoteModel>('notes');
await Hive.openBox('settings');
}
/// 获取Box实例
static Box<T> getBox<T>(String boxName) {
if (!Hive.isBoxOpen(boxName)) {
throw StateError('Box "$boxName"未打开');
}
return Hive.box<T>(boxName);
}
/// 关闭所有Box
static Future<void> dispose() async {
await Hive.close();
}
}
3. 仓储层实现
dart
// lib/features/notes/data/repositories/note_repository_impl.dart
import 'package:dartz/dartz.dart';
import 'package:hive/hive.dart';
import 'package:equatable/equatable.dart';
import '../../../../core/error/failures.dart';
import '../../domain/entities/note.dart';
import '../../domain/repositories/note_repository.dart';
import '../models/note_model.dart';
import '../../../../core/storage/hive_service.dart';
class NoteRepositoryImpl implements NoteRepository {
final Box<NoteModel> _noteBox;
NoteRepositoryImpl() : _noteBox = HiveService.getBox<NoteModel>('notes');
@override
Future<Either<Failure, Note>> addNote(Note note) async {
try {
final noteModel = NoteModel(
id: note.id,
title: note.title,
content: note.content,
createdAt: note.createdAt,
updatedAt: note.updatedAt,
tags: note.tags,
);
await _noteBox.put(note.id, noteModel);
return Right(note);
} catch (e) {
return Left(CacheFailure(message: e.toString()));
}
}
@override
Future<Either<Failure, List<Note>>> getAllNotes() async {
try {
final notes = _noteBox.values
.map((model) => Note(
id: model.id,
title: model.title,
content: model.content,
createdAt: model.createdAt,
updatedAt: model.updatedAt,
tags: model.tags,
))
.toList();
return Right(notes);
} catch (e) {
return Left(CacheFailure(message: e.toString()));
}
}
@override
Future<Either<Failure, Note?>> getNoteById(String id) async {
try {
final model = _noteBox.get(id);
if (model == null) {
return const Right(null);
}
final note = Note(
id: model.id,
title: model.title,
content: model.content,
createdAt: model.createdAt,
updatedAt: model.updatedAt,
tags: model.tags,
);
return Right(note);
} catch (e) {
return Left(CacheFailure(message: e.toString()));
}
}
// 实现其他方法...
}
三、SQLite:结构化数据存储方案
对于需要复杂查询和关系管理的数据,SQLite 是最佳选择:
dart
// lib/core/database/app_database.dart
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
import 'package:flutter/foundation.dart';
/// SQLite数据库管理类
class AppDatabase {
static Database? _database;
static const String _dbName = 'app_database.db';
static const int _version = 2; // 当前数据库版本
/// 获取数据库单例
static Future<Database> get instance async {
if (_database != null) return _database!;
_database = await _initDatabase();
return _database!;
}
/// 初始化数据库
static Future<Database> _initDatabase() async {
final databasesPath = await getDatabasesPath();
final path = join(databasesPath, _dbName);
return await openDatabase(
path,
version: _version,
onCreate: _onCreate,
onUpgrade: _onUpgrade,
onDowngrade: _onDowngrade,
);
}
/// 数据库创建时调用
static Future<void> _onCreate(Database db, int version) async {
// 创建用户表
await db.execute('''
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
email TEXT UNIQUE NOT NULL,
name TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
''');
// 创建订单表
await db.execute('''
CREATE TABLE orders (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
total_amount REAL NOT NULL,
status TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE
)
''');
}
/// 数据库升级时调用
static Future<void> _onUpgrade(Database db, int oldVersion, int newVersion) async {
debugPrint('升级数据库: $oldVersion -> $newVersion');
if (oldVersion < 2) {
// 版本1升级到版本2:添加用户头像字段
await db.execute('ALTER TABLE users ADD COLUMN avatar_url TEXT');
}
}
/// 数据库降级时调用
static Future<void> _onDowngrade(Database db, int oldVersion, int newVersion) async {
// 处理降级逻辑...
}
/// 关闭数据库
static Future<void> close() async {
if (_database != null) {
await _database!.close();
_database = null;
}
}
/// 执行事务
static Future<T> transaction<T>(Future<T> Function(Database) action) async {
final db = await instance;
return await db.transaction(action);
}
}
数据访问层示例:
dart
// lib/features/users/data/datasources/user_local_data_source.dart
import 'package:sqflite/sqflite.dart';
import '../../../../core/database/app_database.dart';
import '../models/user_model.dart';
abstract class UserLocalDataSource {
Future<UserModel> getUserById(int id);
Future<int> insertUser(UserModel user);
Future<List<UserModel>> getAllUsers();
}
class UserLocalDataSourceImpl implements UserLocalDataSource {
@override
Future<UserModel> getUserById(int id) async {
final db = await AppDatabase.instance;
final maps = await db.query(
'users',
where: 'id = ?',
whereArgs: [id],
limit: 1,
);
if (maps.isNotEmpty) {
return UserModel.fromMap(maps.first);
} else {
throw Exception('User not found');
}
}
@override
Future<int> insertUser(UserModel user) async {
return await AppDatabase.transaction((db) async {
return await db.insert(
'users',
user.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace,
);
});
}
// 其他方法实现...
}
四、存储方案选型指南
| 特性 | SharedPreferences | Hive | SQLite |
|---|---|---|---|
| 数据类型 | 简单键值对 | 对象、集合、自定义类型 | 结构化关系数据 |
| 查询能力 | 仅按 key 查询 | 基本查询、索引支持 | SQL 查询、JOIN、事务 |
| 性能 | 快(小数据量) | 极快(所有数据内存中) | 稳定(适合大数据量) |
| 数据大小 | 适合 < 1MB | 适合 < 100MB | 无限制 |
| 加密支持 | 无(需自行加密) | 内置加密 | 需自行实现 |
| 学习曲线 | 低 | 中 | 高 |
| 适用场景 | 配置、Token、简单偏好设置 | 缓存、复杂对象、本地列表 | 用户数据、订单、关系型数据 |
五、企业级存储最佳实践
-
分层架构设计
- 数据层:原始存储实现(SharedPreferences/Hive/SQLite)
- 仓储层:封装数据操作逻辑,提供清晰接口
- 领域层:定义业务实体和规则,与存储实现解耦
-
错误处理策略
- 使用 Either 模式区分成功 / 失败结果
- 统一的异常处理和日志记录
- 适当的重试机制和回滚策略
-
性能优化技巧
- 批量操作使用事务
- 大数据集使用分页加载
- 索引优化(SQLite)
- 内存缓存热点数据
-
安全考量
- 敏感数据加密存储
- 避免存储明文密码
- 使用安全的密钥管理方案
-
测试策略
- 抽象存储接口便于 Mock 测试
- 单元测试覆盖核心存储逻辑
- 集成测试验证端到端数据流程
总结
Flutter 本地存储的核心要点:
-
选型匹配场景:根据数据复杂度和访问模式选择合适的存储方案,简单配置用 SharedPreferences,复杂对象用 Hive,结构化数据用 SQLite。
-
架构分层设计:通过仓储模式封装存储实现,隔离业务逻辑与数据访问,提高代码可维护性和可测试性。
-
关注性能与安全:合理使用事务、索引和缓存优化性能,对敏感数据实施加密保护,遵循数据安全最佳实践。
通过遵循这些最佳实践,你可以构建出健壮、高效且易于维护的 Flutter 本地存储系统,满足从简单到复杂的应用需求。