我来为您详细介绍Flutter主流的本地存储方案,包括使用场景、区别和实际代码示例。 主要包括 SharedPreferences、Hive、SQLite、path_provider、ObjectBox等
1. Shared Preferences
使用场景
- 简单的键值对存储
- 用户偏好设置(主题、语言等)
- 登录状态、用户配置
- 小型数据缓存
特点
- 基于平台原生存储(iOS的NSUserDefaults,Android的SharedPreferences)
- 只支持基本数据类型(String, int, double, bool, List)
- 性能中等,适合少量数据
实际代码示例
dart
import 'package:shared_preferences/shared_preferences.dart';
class SharedPreferencesService {
static const String _themeKey = 'theme';
static const String _languageKey = 'language';
static const String _userTokenKey = 'user_token';
static const String _firstLaunchKey = 'first_launch';
// 保存主题设置
static Future<void> saveTheme(String theme) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString(_themeKey, theme);
}
// 获取主题设置
static Future<String?> getTheme() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString(_themeKey);
}
// 保存用户token
static Future<void> saveUserToken(String token) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString(_userTokenKey, token);
}
// 获取用户token
static Future<String?> getUserToken() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString(_userTokenKey);
}
// 标记首次启动
static Future<void> markFirstLaunch() async {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool(_firstLaunchKey, false);
}
// 检查是否首次启动
static Future<bool> isFirstLaunch() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getBool(_firstLaunchKey) ?? true;
}
// 清除所有数据
static Future<void> clearAll() async {
final prefs = await SharedPreferences.getInstance();
await prefs.clear();
}
}
2. Hive
使用场景
- 复杂对象存储
- 大量数据存储
- 需要高性能读写的场景
- 离线数据缓存
特点
- 纯Dart实现,跨平台一致性好
- 支持自定义对象存储
- 高性能(比SQLite更快)
- 支持加密
实际代码示例
dart
import 'package:hive/hive.dart';
part 'user_model.g.dart';
@HiveType(typeId: 0)
class UserModel extends HiveObject {
@HiveField(0)
final String id;
@HiveField(1)
final String name;
@HiveField(2)
final String email;
@HiveField(3)
final DateTime createdAt;
@HiveField(4)
final Map<String, dynamic> preferences;
UserModel({
required this.id,
required this.name,
required this.email,
required this.createdAt,
required this.preferences,
});
}
part 'product_model.g.dart';
@HiveType(typeId: 1)
class ProductModel extends HiveObject {
@HiveField(0)
final String id;
@HiveField(1)
final String name;
@HiveField(2)
final double price;
@HiveField(3)
final int stock;
@HiveField(4)
final List<String> categories;
ProductModel({
required this.id,
required this.name,
required this.price,
required this.stock,
required this.categories,
});
}
class HiveService {
static const String _userBox = 'users';
static const String _productBox = 'products';
static const String _settingsBox = 'settings';
static Future<void> init() async {
await Hive.initFlutter();
// 注册适配器
Hive.registerAdapter(UserModelAdapter());
Hive.registerAdapter(ProductModelAdapter());
// 打开盒子
await Hive.openBox<UserModel>(_userBox);
await Hive.openBox<ProductModel>(_productBox);
await Hive.openBox(_settingsBox); // 普通盒子,存储基本类型
}
// 用户相关操作
static Future<void> saveUser(UserModel user) async {
final box = Hive.box<UserModel>(_userBox);
await box.put(user.id, user);
}
static UserModel? getUser(String userId) {
final box = Hive.box<UserModel>(_userBox);
return box.get(userId);
}
static List<UserModel> getAllUsers() {
final box = Hive.box<UserModel>(_userBox);
return box.values.toList();
}
// 产品相关操作
static Future<void> saveProduct(ProductModel product) async {
final box = Hive.box<ProductModel>(_productBox);
await box.put(product.id, product);
}
static List<ProductModel> getProductsByCategory(String category) {
final box = Hive.box<ProductModel>(_productBox);
return box.values
.where((product) => product.categories.contains(category))
.toList();
}
// 批量操作
static Future<void> saveProducts(List<ProductModel> products) async {
final box = Hive.box<ProductModel>(_productBox);
final Map<String, ProductModel> data = {};
for (var product in products) {
data[product.id] = product;
}
await box.putAll(data);
}
// 使用事务
static Future<void> updateProductStock(String productId, int newStock) async {
final box = Hive.box<ProductModel>(_productBox);
await Hive.runInTransaction(() async {
final product = box.get(productId);
if (product != null) {
final updatedProduct = ProductModel(
id: product.id,
name: product.name,
price: product.price,
stock: newStock,
categories: product.categories,
);
await box.put(productId, updatedProduct);
}
});
}
}
3. SQLite (sqflite)
使用场景
- 复杂的关系型数据
- 需要SQL查询的场景
- 数据统计分析
- 大量结构化数据
特点
- 完整的SQL支持
- 支持事务
- 成熟稳定
- 性能优秀
实际代码示例
dart
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
class OrderModel {
final int? id;
final String orderId;
final String userId;
final double totalAmount;
final DateTime orderDate;
final String status;
final List<OrderItem> items;
OrderModel({
this.id,
required this.orderId,
required this.userId,
required this.totalAmount,
required this.orderDate,
required this.status,
required this.items,
});
Map<String, dynamic> toMap() {
return {
'id': id,
'order_id': orderId,
'user_id': userId,
'total_amount': totalAmount,
'order_date': orderDate.millisecondsSinceEpoch,
'status': status,
};
}
}
class OrderItem {
final int? id;
final String orderId;
final String productId;
final int quantity;
final double unitPrice;
OrderItem({
this.id,
required this.orderId,
required this.productId,
required this.quantity,
required this.unitPrice,
});
Map<String, dynamic> toMap() {
return {
'id': id,
'order_id': orderId,
'product_id': productId,
'quantity': quantity,
'unit_price': unitPrice,
};
}
}
class DatabaseService {
static Database? _database;
static const int _version = 1;
static Future<Database> get database async {
if (_database != null) return _database!;
_database = await _initDatabase();
return _database!;
}
static Future<Database> _initDatabase() async {
final path = join(await getDatabasesPath(), 'ecommerce.db');
return openDatabase(
path,
version: _version,
onCreate: (db, version) async {
// 创建订单表
await db.execute('''
CREATE TABLE orders(
id INTEGER PRIMARY KEY AUTOINCREMENT,
order_id TEXT UNIQUE NOT NULL,
user_id TEXT NOT NULL,
total_amount REAL NOT NULL,
order_date INTEGER NOT NULL,
status TEXT NOT NULL
)
''');
// 创建订单项表
await db.execute('''
CREATE TABLE order_items(
id INTEGER PRIMARY KEY AUTOINCREMENT,
order_id TEXT NOT NULL,
product_id TEXT NOT NULL,
quantity INTEGER NOT NULL,
unit_price REAL NOT NULL,
FOREIGN KEY (order_id) REFERENCES orders (order_id)
)
''');
// 创建索引
await db.execute('CREATE INDEX idx_orders_user_id ON orders(user_id)');
await db.execute('CREATE INDEX idx_orders_date ON orders(order_date)');
},
onUpgrade: (db, oldVersion, newVersion) async {
// 数据库升级逻辑
if (oldVersion < 2) {
// 添加新字段或表
}
},
);
}
// 插入订单(使用事务)
static Future<int> insertOrder(OrderModel order) async {
final db = await database;
return await db.transaction((txn) async {
// 插入订单
final orderId = await txn.insert(
'orders',
order.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace,
);
// 插入订单项
for (var item in order.items) {
await txn.insert(
'order_items',
item.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
return orderId;
});
}
// 查询用户订单(带分页)
static Future<List<OrderModel>> getUserOrders(
String userId, {
int page = 1,
int pageSize = 20,
}) async {
final db = await database;
final offset = (page - 1) * pageSize;
final List<Map<String, dynamic>> orderMaps = await db.query(
'orders',
where: 'user_id = ?',
whereArgs: [userId],
orderBy: 'order_date DESC',
limit: pageSize,
offset: offset,
);
final orders = <OrderModel>[];
for (var orderMap in orderMaps) {
// 查询订单项
final List<Map<String, dynamic>> itemMaps = await db.query(
'order_items',
where: 'order_id = ?',
whereArgs: [orderMap['order_id']],
);
final items = itemMaps.map((itemMap) => OrderItem(
id: itemMap['id'],
orderId: itemMap['order_id'],
productId: itemMap['product_id'],
quantity: itemMap['quantity'],
unitPrice: itemMap['unit_price'],
)).toList();
orders.add(OrderModel(
id: orderMap['id'],
orderId: orderMap['order_id'],
userId: orderMap['user_id'],
totalAmount: orderMap['total_amount'],
orderDate: DateTime.fromMillisecondsSinceEpoch(orderMap['order_date']),
status: orderMap['status'],
items: items,
));
}
return orders;
}
// 复杂查询:统计用户消费
static Future<Map<String, dynamic>> getUserOrderStats(String userId) async {
final db = await database;
final result = await db.rawQuery('''
SELECT
COUNT(*) as total_orders,
SUM(total_amount) as total_spent,
AVG(total_amount) as avg_order_value,
MAX(total_amount) as max_order_value
FROM orders
WHERE user_id = ? AND status = 'completed'
''', [userId]);
if (result.isNotEmpty) {
return {
'total_orders': result.first['total_orders'] ?? 0,
'total_spent': result.first['total_spent'] ?? 0.0,
'avg_order_value': result.first['avg_order_value'] ?? 0.0,
'max_order_value': result.first['max_order_value'] ?? 0.0,
};
}
return {
'total_orders': 0,
'total_spent': 0.0,
'avg_order_value': 0.0,
'max_order_value': 0.0,
};
}
}
4. 文件存储 (path_provider)
使用场景
- 大文件存储(图片、文档等)
- 自定义文件格式
- 需要直接文件操作的场景
- 应用日志记录
特点
- 灵活性强
- 适合大文件
- 需要手动管理文件路径
实际代码示例
dart
import 'dart:io';
import 'dart:convert';
import 'package:path_provider/path_provider.dart';
class FileStorageService {
// 获取不同类型的目录
static Future<Directory> get documentsDirectory async {
return await getApplicationDocumentsDirectory();
}
static Future<Directory> get tempDirectory async {
return await getTemporaryDirectory();
}
static Future<Directory> get externalStorageDirectory async {
return await getExternalStorageDirectory() ?? await documentsDirectory;
}
// 保存JSON配置文件
static Future<void> saveConfig(Map<String, dynamic> config) async {
final dir = await documentsDirectory;
final file = File('${dir.path}/app_config.json');
await file.writeAsString(json.encode(config));
}
// 读取JSON配置文件
static Future<Map<String, dynamic>> loadConfig() async {
try {
final dir = await documentsDirectory;
final file = File('${dir.path}/app_config.json');
if (await file.exists()) {
final contents = await file.readAsString();
return json.decode(contents);
}
} catch (e) {
print('Error loading config: $e');
}
return {};
}
// 保存图片文件
static Future<String> saveImage(File imageFile, String fileName) async {
final dir = await documentsDirectory;
final imagesDir = Directory('${dir.path}/images');
if (!await imagesDir.exists()) {
await imagesDir.create(recursive: true);
}
final newPath = '${imagesDir.path}/$fileName';
await imageFile.copy(newPath);
return newPath;
}
// 保存应用日志
static Future<void> log(String message) async {
try {
final dir = await documentsDirectory;
final logFile = File('${dir.path}/app.log');
final timestamp = DateTime.now().toIso8601String();
final logEntry = '$timestamp: $message\n';
// 追加写入
final sink = logFile.openWrite(mode: FileMode.append);
sink.write(logEntry);
await sink.close();
// 控制日志文件大小(最大10MB)
await _rotateLogFile(logFile);
} catch (e) {
print('Error writing log: $e');
}
}
static Future<void> _rotateLogFile(File logFile) async {
const maxSize = 10 * 1024 * 1024; // 10MB
if (await logFile.exists()) {
final length = await logFile.length();
if (length > maxSize) {
// 读取最后1000行
final lines = await logFile.readAsLines();
final recentLines = lines.length > 1000 ? lines.sublist(lines.length - 1000) : lines;
await logFile.writeAsString(recentLines.join('\n') + '\n');
}
}
}
// 备份数据到文件
static Future<void> backupData(Map<String, dynamic> data) async {
final dir = await documentsDirectory;
final backupDir = Directory('${dir.path}/backups');
if (!await backupDir.exists()) {
await backupDir.create(recursive: true);
}
final timestamp = DateTime.now().millisecondsSinceEpoch;
final backupFile = File('${backupDir.path}/backup_$timestamp.json');
await backupFile.writeAsString(json.encode(data));
// 清理旧的备份文件(保留最近5个)
await _cleanOldBackups(backupDir);
}
static Future<void> _cleanOldBackups(Directory backupDir) async {
final files = await backupDir.list().toList();
final backupFiles = files.whereType<File>().toList();
if (backupFiles.length > 5) {
// 按修改时间排序,删除最旧的
backupFiles.sort((a, b) => a.statSync().modified.compareTo(b.statSync().modified));
for (int i = 0; i < backupFiles.length - 5; i++) {
await backupFiles[i].delete();
}
}
}
}
5. ObjectBox
使用场景
- 超高性能需求
- 大量对象存储
- 实时数据同步
- 复杂对象关系
特点
- 性能极高
- 支持实时查询
- 自动关系管理
- 学习曲线较陡
实际代码示例
dart
import 'package:objectbox/objectbox.dart';
@Entity()
class Customer {
int id = 0;
String name;
String email;
@Property(unique: true)
final String customerId;
final ToMany<Order> orders = ToMany<Order>();
Customer({
this.id = 0,
required this.name,
required this.email,
required this.customerId,
});
}
@Entity()
class Order {
int id = 0;
double totalAmount;
DateTime orderDate;
String status;
final ToOne<Customer> customer = ToOne<Customer>();
final ToMany<Product> products = ToMany<Product>();
Order({
this.id = 0,
required this.totalAmount,
required this.orderDate,
required this.status,
});
}
class ObjectBoxService {
late Store store;
late Box<Customer> customerBox;
late Box<Order> orderBox;
Future<void> init() async {
store = await openStore();
customerBox = store.box<Customer>();
orderBox = store.box<Order>();
}
// 保存客户
int saveCustomer(Customer customer) {
return customerBox.put(customer);
}
// 查询客户(支持复杂条件)
List<Customer> findCustomersByName(String name) {
final query = customerBox.query(
Customer_.name.contains(name, caseSensitive: false)
).build();
return query.find();
}
// 实时查询(监听数据变化)
Stream<List<Customer>> watchCustomers() {
final query = customerBox.query().build();
return query.watch(triggerImmediately: true).map((query) => query.find());
}
}
使用区别对比
特性 | SharedPreferences | Hive | SQLite | 文件存储 | ObjectBox |
---|---|---|---|---|---|
数据类型 | 基本类型 | 自定义对象 | 结构化数据 | 任意数据 | 复杂对象 |
性能 | 中等 | 高 | 高 | 中等 | 极高 |
查询能力 | 无 | 有限 | 完整SQL | 无 | 实时查询 |
事务支持 | 无 | 有 | 有 | 无 | 有 |
加密支持 | 无 | 有 | 有 | 需手动 | 有 |
学习曲线 | 简单 | 中等 | 中等 | 简单 | 较陡 |
适用场景 | 配置项 | 对象存储 | 关系数据 | 大文件 | 高性能 |
综合使用示例
dart
class StorageManager {
static Future<void> init() async {
// 初始化所有存储方案
await HiveService.init();
await DatabaseService.database; // 初始化SQLite
await ObjectBoxService().init(); // 如果有ObjectBox
}
// 根据数据类型选择合适的存储方案
static dynamic saveData(String type, dynamic data) {
switch (type) {
case 'user_preferences':
return SharedPreferencesService.saveUserPreferences(data);
case 'user_object':
return HiveService.saveUser(data);
case 'order_data':
return DatabaseService.insertOrder(data);
case 'large_file':
return FileStorageService.saveFile(data);
case 'high_perf_object':
return ObjectBoxService().saveObject(data);
default:
throw Exception('Unsupported data type: $type');
}
}
}
选择建议
- 简单配置:SharedPreferences
- 对象存储:Hive(平衡性能和学习成本)
- 关系数据:SQLite(需要复杂查询时)
- 大文件:文件存储
- 极致性能:ObjectBox
根据您的具体需求选择合适的存储方案,或者组合使用以获得最佳效果。