在移动应用程序中,持久化存储是必不可少的功能,它允许应用程序在关闭后仍然保留数据。Flutter 提供了多种持久化存储方案,可以根据数据的类型、大小和访问需求选择合适的方案。
1. shared_preferences (键值对存储)
shared_preferences 是一个轻量级的键值对存储插件,适用于存储简单的配置信息、用户偏好设置、登录状态等。它在 Android 上使用 SharedPreferences,在 iOS 上使用 NSUserDefaults。
pubspec.yaml 中添加 shared_preferences 依赖。
dependencies:
shared_preferences: ^2.2.2 # 使用最新版本
```
运行 flutter pub get。
import 'package:shared_preferences/shared_preferences.dart';
Future<void> saveSettings() async {
final prefs = await SharedPreferences.getInstance();
// 存储数据
await prefs.setBool('isDarkMode', true);
await prefs.setInt('fontSize', 16);
await prefs.setString('username', 'Alice');
await prefs.setStringList('recentSearches', ['Flutter', 'Dart', 'Widgets']);
print('设置已保存');
}
Future<void> loadSettings() async {
final prefs = await SharedPreferences.getInstance();
// 读取数据
final bool? isDarkMode = prefs.getBool('isDarkMode');
final int? fontSize = prefs.getInt('fontSize');
final String? username = prefs.getString('username');
final List<String>? recentSearches = prefs.getStringList('recentSearches');
print('isDarkMode: $isDarkMode');
print('fontSize: $fontSize');
print('username: $username');
print('recentSearches: $recentSearches');
}
Future<void> removeSetting() async {
final prefs = await SharedPreferences.getInstance();
await prefs.remove('username'); // 移除某个键值对
print('username 已移除');
}
Future<void> clearAllSettings() async {
final prefs = await SharedPreferences.getInstance();
await prefs.clear(); // 清除所有键值对
print('所有设置已清除');
}
void main() async {
WidgetsFlutterBinding.ensureInitialized(); // 确保 Flutter 绑定已初始化
await saveSettings();
await loadSettings();
await removeSetting();
await loadSettings();
await clearAllSettings();
await loadSettings();
}
2. path_provider (文件存储)
path_provider 插件用于获取设备上常用目录的路径,例如应用程序的文档目录、临时目录等。结合 Dart 的 dart:io 库,可以实现文件的读写操作。
pubspec.yaml 中添加 path_provider 依赖。
dependencies:
path_provider: ^2.1.1 # 使用最新版本
```
运行 flutter pub get。
import 'dart:io';
import 'package:path_provider/path_provider.dart';
Future<String> _getLocalPath() async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Future<File> _getLocalFile() async {
final path = await _getLocalPath();
return File('$path/my_data.txt');
}
Future<File> writeData(String data) async {
final file = await _getLocalFile();
return file.writeAsString(data);
}
Future<String> readData() async {
try {
final file = await _getLocalFile();
final contents = await file.readAsString();
return contents;
} catch (e) {
return '读取失败: $e';
}
}
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await writeData('Hello, Flutter File Storage!');
print('写入数据: ${await readData()}');
}
3. sqflite (SQLite 数据库)
sqflite 是一个 Flutter 插件,提供了 SQLite 数据库的接口。它适用于存储结构化数据,例如用户列表、商品信息、聊天记录等。对于需要复杂查询和大量数据的场景,SQLite 是一个很好的选择。
pubspec.yaml 中添加 sqflite 依赖。
dependencies:
sqflite: ^2.3.0 # 使用最新版本
path: ^1.8.3 # 用于处理路径
```
运行 flutter pub get。
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
class DatabaseHelper {
static Database? _database;
static const String _databaseName = 'my_database.db';
static const int _databaseVersion = 1;
static const String tableName = 'todos';
static const String columnId = 'id';
static const String columnTitle = 'title';
static const String columnIsCompleted = 'isCompleted';
Future<Database> get database async {
if (_database != null) return _database!;
_database = await _initDatabase();
return _database!;
}
_initDatabase() async {
String path = join(await getDatabasesPath(), _databaseName);
return await openDatabase(path,
version: _databaseVersion,
onCreate: _onCreate);
}
Future _onCreate(Database db, int version) async {
await db.execute('''
CREATE TABLE $tableName (
$columnId INTEGER PRIMARY KEY AUTOINCREMENT,
$columnTitle TEXT NOT NULL,
$columnIsCompleted INTEGER NOT NULL
)
''');
}
Future<int> insertTodo(Map<String, dynamic> row) async {
Database db = await database;
return await db.insert(tableName, row);
}
Future<List<Map<String, dynamic>>> queryAllTodos() async {
Database db = await database;
return await db.query(tableName);
}
Future<int> updateTodo(Map<String, dynamic> row) async {
Database db = await database;
int id = row[columnId];
return await db.update(tableName, row,
where: '$columnId = ?', whereArgs: [id]);
}
Future<int> deleteTodo(int id) async {
Database db = await database;
return await db.delete(tableName, where: '$columnId = ?', whereArgs: [id]);
}
}
持久化存储是几乎所有实际应用都需要的核心功能。选择合适的存储方案取决于数据的特性和应用的需求。
案例:一个简单的用户设置管理应用 (使用 shared_preferences)
我们将创建一个应用,允许用户设置主题模式(亮/暗)和通知开关,并将这些设置持久化存储,以便下次打开应用时能够恢复。
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class UserSettingsScreen extends StatefulWidget {
const UserSettingsScreen({super.key});
@override
State<UserSettingsScreen> createState() => _UserSettingsScreenState();
}
class _UserSettingsScreenState extends State<UserSettingsScreen> {
bool _isDarkMode = false;
bool _enableNotifications = true;
@override
void initState() {
super.initState();
_loadSettings();
}
// 加载用户设置
Future<void> _loadSettings() async {
final prefs = await SharedPreferences.getInstance();
setState(() {
_isDarkMode = prefs.getBool('isDarkMode') ?? false;
_enableNotifications = prefs.getBool('enableNotifications') ?? true;
});
}
// 保存主题模式设置
Future<void> _saveDarkMode(bool value) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool('isDarkMode', value);
setState(() {
_isDarkMode = value;
});
}
// 保存通知设置
Future<void> _saveNotifications(bool value) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool('enableNotifications', value);
setState(() {
_enableNotifications = value;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('用户设置'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: <Widget>[
SwitchListTile(
title: const Text('深色模式'),
value: _isDarkMode,
onChanged: _saveDarkMode,
),
SwitchListTile(
title: const Text('启用通知'),
value: _enableNotifications,
onChanged: _saveNotifications,
),
const Divider(),
ElevatedButton(
onPressed: () async {
final prefs = await SharedPreferences.getInstance();
await prefs.clear();
_loadSettings(); // 重新加载以反映清除后的默认值
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('所有设置已重置')),
);
},
child: const Text('重置所有设置'),
),
],
),
),
);
}
}
void main() {
// 确保 Flutter 绑定已初始化,因为 SharedPreferences 需要访问平台服务
WidgetsFlutterBinding.ensureInitialized();
runApp(MaterialApp(
home: const UserSettingsScreen(),
theme: ThemeData(
brightness: Brightness.light, // 默认亮色模式
),
darkTheme: ThemeData(
brightness: Brightness.dark, // 深色模式
),
themeMode: ThemeMode.system, // 默认跟随系统主题
// 实际应用中,这里可以根据 _isDarkMode 动态设置 themeMode
// 例如: themeMode: _isDarkMode ? ThemeMode.dark : ThemeMode.light,
));
}
案例分析:
WidgetsFlutterBinding.ensureInitialized():在 main() 函数中调用此方法非常重要,它确保 Flutter 框架的绑定已初始化,这是 shared_preferences 等插件能够正常工作的前提。SharedPreferences.getInstance():这是一个异步方法,用于获取 SharedPreferences 的单例实例。由于它是异步的,所以需要使用 await。_loadSettings():在 initState 中调用,用于在屏幕加载时从 shared_preferences 中读取之前保存的设置。prefs.getBool('key') ?? false 使用了空安全操作符 ??,如果读取不到值(例如第一次运行应用),则提供一个默认值。_saveDarkMode() 和 _saveNotifications():当用户切换开关时,这些方法会被调用。它们将新的设置值保存到 shared_preferences 中,并更新 _isDarkMode 和 _enableNotifications 状态,从而触发 UI 重建。prefs.clear():用于清除 shared_preferences 中存储的所有数据。这个案例清晰地展示了如何使用 shared_preferences 在 Flutter 应用中进行轻量级的持久化存储。它非常适合存储用户偏好、应用配置等简单数据。对于更复杂的数据结构或大量数据,则需要考虑文件存储或数据库解决方案。