Appearance
Flutter数据存储
在移动应用开发中,数据存储是至关重要的功能。Flutter提供了多种数据存储方案,从简单的键值对存储到复杂的数据库系统。本章将详细介绍Flutter中的各种数据存储方式及其适用场景。
本地存储概述
Flutter中的数据存储主要分为以下几类:
- 键值对存储:适用于存储简单的配置数据
- 文件存储:适用于存储文件类型的大量数据
- 数据库存储:适用于结构化数据的存储和查询
- 缓存存储:适用于临时数据的快速读写
SharedPreferences(键值对存储)
SharedPreferences是Flutter中最简单的数据存储方式,适合存储少量的键值对数据,如用户偏好设置、应用配置等。
添加依赖
在pubspec.yaml中添加依赖:
yaml
dependencies:
flutter:
sdk: flutter
shared_preferences: ^2.2.2
基础使用
dart
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class SharedPreferencesDemo extends StatefulWidget {
@override
_SharedPreferencesDemoState createState() => _SharedPreferencesDemoState();
}
class _SharedPreferencesDemoState extends State<SharedPreferencesDemo> {
String _username = '';
int _age = 0;
bool _isDarkTheme = false;
String _result = '';
@override
void initState() {
super.initState();
_loadData();
}
// 加载数据
Future<void> _loadData() async {
final prefs = await SharedPreferences.getInstance();
setState(() {
_username = prefs.getString('username') ?? '';
_age = prefs.getInt('age') ?? 0;
_isDarkTheme = prefs.getBool('isDarkTheme') ?? false;
});
}
// 保存数据
Future<void> _saveData() async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString('username', _username);
await prefs.setInt('age', _age);
await prefs.setBool('isDarkTheme', _isDarkTheme);
setState(() {
_result = '数据已保存';
});
// 显示提示
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('数据已保存')),
);
}
// 清除特定数据
Future<void> _clearSpecificData() async {
final prefs = await SharedPreferences.getInstance();
await prefs.remove('username');
setState(() {
_username = '';
_result = '用户名已清除';
});
}
// 清除所有数据
Future<void> _clearAllData() async {
final prefs = await SharedPreferences.getInstance();
await prefs.clear();
setState(() {
_username = '';
_age = 0;
_isDarkTheme = false;
_result = '所有数据已清除';
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('SharedPreferences 示例')),
body: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
children: [
TextField(
decoration: InputDecoration(
labelText: '用户名',
hintText: '输入用户名',
),
onChanged: (value) => setState(() => _username = value),
controller: TextEditingController(text: _username),
),
SizedBox(height: 16),
TextField(
decoration: InputDecoration(
labelText: '年龄',
hintText: '输入年龄',
),
keyboardType: TextInputType.number,
onChanged: (value) {
if (value.isNotEmpty) {
setState(() => _age = int.tryParse(value) ?? 0);
}
},
controller: TextEditingController(text: _age.toString()),
),
SizedBox(height: 16),
SwitchListTile(
title: Text('深色主题'),
value: _isDarkTheme,
onChanged: (value) => setState(() => _isDarkTheme = value),
),
SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: _saveData,
child: Text('保存数据'),
),
ElevatedButton(
onPressed: _clearSpecificData,
child: Text('清除用户名'),
),
],
),
SizedBox(height: 10),
ElevatedButton(
onPressed: _clearAllData,
child: Text('清除所有数据'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
foregroundColor: Colors.white,
),
),
SizedBox(height: 20),
Card(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('当前状态:', style: Theme.of(context).textTheme.headlineSmall),
SizedBox(height: 10),
Text('用户名: $_username'),
Text('年龄: $_age'),
Text('深色主题: ${_isDarkTheme ? '开启' : '关闭'}'),
if (_result.isNotEmpty) Text('结果: $_result'),
],
),
),
),
],
),
),
);
}
}
SharedPreferences工具类
dart
class SharedPrefsHelper {
static const String _usernameKey = 'username';
static const String _ageKey = 'age';
static const String _isDarkThemeKey = 'isDarkTheme';
static const String _loginStatusKey = 'isLogin';
static const String _tokenKey = 'token';
static Future<SharedPreferences> _getInstance() async {
return await SharedPreferences.getInstance();
}
// 用户名相关
static Future<void> setUsername(String username) async {
final prefs = await _getInstance();
await prefs.setString(_usernameKey, username);
}
static Future<String?> getUsername() async {
final prefs = await _getInstance();
return prefs.getString(_usernameKey);
}
static Future<void> removeUsername() async {
final prefs = await _getInstance();
await prefs.remove(_usernameKey);
}
// 年龄相关
static Future<void> setAge(int age) async {
final prefs = await _getInstance();
await prefs.setInt(_ageKey, age);
}
static Future<int> getAge() async {
final prefs = await _getInstance();
return prefs.getInt(_ageKey) ?? 0;
}
// 主题相关
static Future<void> setDarkTheme(bool isDark) async {
final prefs = await _getInstance();
await prefs.setBool(_isDarkThemeKey, isDark);
}
static Future<bool> isDarkTheme() async {
final prefs = await _getInstance();
return prefs.getBool(_isDarkThemeKey) ?? false;
}
// 登录状态相关
static Future<void> setLoginStatus(bool isLogin) async {
final prefs = await _getInstance();
await prefs.setBool(_loginStatusKey, isLogin);
}
static Future<bool> isLogin() async {
final prefs = await _getInstance();
return prefs.getBool(_loginStatusKey) ?? false;
}
// Token相关
static Future<void> setToken(String token) async {
final prefs = await _getInstance();
await prefs.setString(_tokenKey, token);
}
static Future<String?> getToken() async {
final prefs = await _getInstance();
return prefs.getString(_tokenKey);
}
// 清除登录相关信息
static Future<void> clearLoginInfo() async {
final prefs = await _getInstance();
await prefs.remove(_loginStatusKey);
await prefs.remove(_tokenKey);
await prefs.remove(_usernameKey);
}
// 获取所有键
static Future<List<String>> getAllKeys() async {
final prefs = await _getInstance();
return prefs.getKeys().toList();
}
}
文件存储
Flutter提供了完整的文件系统访问能力,可以存储任意类型的文件。
添加依赖
yaml
dependencies:
flutter:
sdk: flutter
path_provider: ^2.1.1
基础文件操作
dart
import 'dart:io';
import 'package:path_provider/path_provider.dart';
class FileStorageDemo extends StatefulWidget {
@override
_FileStorageDemoState createState() => _FileStorageDemoState();
}
class _FileStorageDemoState extends State<FileStorageDemo> {
String _inputText = '';
String _readText = '';
String _status = '';
// 获取应用文档目录
Future<String> _getAppDocDir() async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
// 写入文件
Future<void> _writeToFile() async {
try {
final directory = await getApplicationDocumentsDirectory();
final file = File('${directory.path}/my_file.txt');
await file.writeAsString(_inputText);
setState(() {
_status = '文件写入成功';
});
} catch (e) {
setState(() {
_status = '写入失败: $e';
});
}
}
// 读取文件
Future<void> _readFromFile() async {
try {
final directory = await getApplicationDocumentsDirectory();
final file = File('${directory.path}/my_file.txt');
if (await file.exists()) {
final content = await file.readAsString();
setState(() {
_readText = content;
_status = '文件读取成功';
});
} else {
setState(() {
_readText = '文件不存在';
_status = '文件不存在';
});
}
} catch (e) {
setState(() {
_readText = '';
_status = '读取失败: $e';
});
}
}
// 删除文件
Future<void> _deleteFile() async {
try {
final directory = await getApplicationDocumentsDirectory();
final file = File('${directory.path}/my_file.txt');
if (await file.exists()) {
await file.delete();
setState(() {
_readText = '';
_status = '文件删除成功';
});
} else {
setState(() {
_status = '文件不存在';
});
}
} catch (e) {
setState(() {
_status = '删除失败: $e';
});
}
}
// 获取文件信息
Future<void> _getFileInfo() async {
try {
final directory = await getApplicationDocumentsDirectory();
final file = File('${directory.path}/my_file.txt');
if (await file.exists()) {
final stat = await file.stat();
final length = await file.length();
setState(() {
_status = '文件大小: ${length} bytes, 修改时间: ${stat.modified}';
});
} else {
setState(() {
_status = '文件不存在';
});
}
} catch (e) {
setState(() {
_status = '获取信息失败: $e';
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('文件存储示例')),
body: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
children: [
TextField(
decoration: InputDecoration(
labelText: '输入要保存的文本',
hintText: '在此输入文本...',
border: OutlineInputBorder(),
),
maxLines: 3,
onChanged: (value) => setState(() => _inputText = value),
),
SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: _writeToFile,
child: Text('写入文件'),
),
ElevatedButton(
onPressed: _readFromFile,
child: Text('读取文件'),
),
],
),
SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: _deleteFile,
child: Text('删除文件'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
foregroundColor: Colors.white,
),
),
ElevatedButton(
onPressed: _getFileInfo,
child: Text('文件信息'),
),
],
),
SizedBox(height: 20),
if (_status.isNotEmpty)
Card(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Text('状态: $_status'),
),
),
SizedBox(height: 20),
if (_readText.isNotEmpty)
Expanded(
child: Card(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('读取的内容:', style: Theme.of(context).textTheme.headlineSmall),
SizedBox(height: 10),
Expanded(
child: SingleChildScrollView(
child: Text(_readText),
),
),
],
),
),
),
),
],
),
),
);
}
}
图片文件存储
dart
import 'dart:typed_data';
import 'dart:ui' as ui;
class ImageStorageDemo extends StatefulWidget {
@override
_ImageStorageDemoState createState() => _ImageStorageDemoState();
}
class _ImageStorageDemoState extends State<ImageStorageDemo> {
String _status = '';
String _imagePath = '';
// 保存图片
Future<void> _saveImage() async {
try {
// 这里只是一个示例,实际应用中可能是从相机或相册获取的图片
// 为了演示目的,我们创建一个简单的字节数组
final imageData = Uint8List.fromList([
// 这里应该是实际的图片数据
// 实际应用中可以从ImagePicker获取
]);
final directory = await getApplicationDocumentsDirectory();
final imagePath = '${directory.path}/image_${DateTime.now().millisecondsSinceEpoch}.png';
final imageFile = File(imagePath);
await imageFile.writeAsBytes(imageData);
setState(() {
_imagePath = imagePath;
_status = '图片保存成功';
});
} catch (e) {
setState(() {
_status = '图片保存失败: $e';
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('图片存储示例')),
body: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
children: [
ElevatedButton(
onPressed: _saveImage,
child: Text('保存图片'),
),
SizedBox(height: 20),
if (_status.isNotEmpty)
Card(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Text(_status),
),
),
if (_imagePath.isNotEmpty)
Card(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('图片路径:', style: Theme.of(context).textTheme.headlineSmall),
Text(_imagePath),
],
),
),
),
],
),
),
);
}
}
SQLite数据库
SQLite是Flutter中处理结构化数据的强大工具,适用于需要复杂查询和关系型数据的应用。
添加依赖
yaml
dependencies:
flutter:
sdk: flutter
sqflite: ^2.3.0
path: ^1.8.3
基础SQLite操作
dart
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
class User {
final int? id;
final String name;
final String email;
final int age;
final DateTime createdAt;
User({
this.id,
required this.name,
required this.email,
required this.age,
required this.createdAt,
});
Map<String, dynamic> toMap() {
return {
'id': id,
'name': name,
'email': email,
'age': age,
'created_at': createdAt.toIso8601String(),
};
}
factory User.fromMap(Map<String, dynamic> map) {
return User(
id: map['id'],
name: map['name'],
email: map['email'],
age: map['age'],
createdAt: DateTime.parse(map['created_at']),
);
}
}
class DatabaseHelper {
static Database? _database;
Future<Database> get database async {
if (_database != null) return _database!;
_database = await _initDatabase();
return _database!;
}
Future<Database> _initDatabase() async {
String path = join(await getDatabasesPath(), 'user_database.db');
return await openDatabase(
path,
version: 1,
onCreate: _createDb,
);
}
Future<void> _createDb(Database db, int version) async {
await db.execute('''
CREATE TABLE users(
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
age INTEGER NOT NULL,
created_at TEXT NOT NULL
)
''');
}
// 插入用户
Future<int> insertUser(User user) async {
final db = await database;
return await db.insert(
'users',
user.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
// 获取所有用户
Future<List<User>> getUsers() async {
final db = await database;
final List<Map<String, dynamic>> maps = await db.query('users');
return List.generate(maps.length, (i) {
return User.fromMap(maps[i]);
});
}
// 根据ID获取用户
Future<User?> getUserById(int id) async {
final db = await database;
final List<Map<String, dynamic>> maps = await db.query(
'users',
where: 'id = ?',
whereArgs: [id],
);
if (maps.isNotEmpty) {
return User.fromMap(maps.first);
}
return null;
}
// 更新用户
Future<int> updateUser(User user) async {
final db = await database;
return await db.update(
'users',
user.toMap(),
where: 'id = ?',
whereArgs: [user.id],
);
}
// 删除用户
Future<int> deleteUser(int id) async {
final db = await database;
return await db.delete(
'users',
where: 'id = ?',
whereArgs: [id],
);
}
// 搜索用户
Future<List<User>> searchUsers(String query) async {
final db = await database;
final List<Map<String, dynamic>> maps = await db.query(
'users',
where: 'name LIKE ? OR email LIKE ?',
whereArgs: ['%$query%', '%$query%'],
);
return List.generate(maps.length, (i) {
return User.fromMap(maps[i]);
});
}
// 关闭数据库
Future<void> close() async {
final db = await database;
db.close();
}
}
class SQLiteDemo extends StatefulWidget {
@override
_SQLiteDemoState createState() => _SQLiteDemoState();
}
class _SQLiteDemoState extends State<SQLiteDemo> {
final DatabaseHelper _dbHelper = DatabaseHelper();
final TextEditingController _nameController = TextEditingController();
final TextEditingController _emailController = TextEditingController();
final TextEditingController _ageController = TextEditingController();
final TextEditingController _searchController = TextEditingController();
List<User> _users = [];
String _status = '';
@override
void initState() {
super.initState();
_loadUsers();
}
Future<void> _loadUsers() async {
final users = await _dbHelper.getUsers();
setState(() {
_users = users;
});
}
Future<void> _addUser() async {
if (_nameController.text.isEmpty ||
_emailController.text.isEmpty ||
_ageController.text.isEmpty) {
setState(() {
_status = '请填写所有字段';
});
return;
}
try {
final user = User(
name: _nameController.text,
email: _emailController.text,
age: int.parse(_ageController.text),
createdAt: DateTime.now(),
);
await _dbHelper.insertUser(user);
_nameController.clear();
_emailController.clear();
_ageController.clear();
await _loadUsers();
setState(() {
_status = '用户添加成功';
});
} catch (e) {
setState(() {
_status = '添加失败: $e';
});
}
}
Future<void> _deleteUser(int id) async {
await _dbHelper.deleteUser(id);
await _loadUsers();
setState(() {
_status = '用户删除成功';
});
}
Future<void> _searchUsers() async {
final query = _searchController.text;
if (query.isEmpty) {
await _loadUsers();
return;
}
final users = await _dbHelper.searchUsers(query);
setState(() {
_users = users;
_status = '搜索完成,找到 ${users.length} 个结果';
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('SQLite数据库示例')),
body: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
children: [
Card(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
children: [
TextField(
controller: _nameController,
decoration: InputDecoration(labelText: '姓名'),
),
TextField(
controller: _emailController,
decoration: InputDecoration(labelText: '邮箱'),
),
TextField(
controller: _ageController,
decoration: InputDecoration(labelText: '年龄'),
keyboardType: TextInputType.number,
),
SizedBox(height: 10),
ElevatedButton(
onPressed: _addUser,
child: Text('添加用户'),
),
],
),
),
),
SizedBox(height: 16),
TextField(
controller: _searchController,
decoration: InputDecoration(
labelText: '搜索用户',
suffixIcon: IconButton(
icon: Icon(Icons.search),
onPressed: _searchUsers,
),
),
onSubmitted: (value) => _searchUsers(),
),
SizedBox(height: 16),
if (_status.isNotEmpty)
Card(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Text(_status),
),
),
SizedBox(height: 10),
Expanded(
child: _users.isEmpty
? Center(child: Text('暂无用户数据'))
: ListView.builder(
itemCount: _users.length,
itemBuilder: (context, index) {
final user = _users[index];
return Card(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
user.name,
style: Theme.of(context).textTheme.headlineSmall,
),
IconButton(
icon: Icon(Icons.delete, color: Colors.red),
onPressed: () => _deleteUser(user.id!),
),
],
),
Text('邮箱: ${user.email}'),
Text('年龄: ${user.age}'),
Text('创建时间: ${user.createdAt}'),
],
),
),
);
},
),
),
],
),
),
);
}
@override
void dispose() {
_dbHelper.close();
super.dispose();
}
}
Hive数据库
Hive是Flutter中一个快速、轻量级的NoSQL数据库,特别适合移动端使用。
添加依赖
yaml
dependencies:
flutter:
sdk: flutter
hive: ^2.2.3
hive_flutter: ^1.1.0
Hive基础操作
dart
import 'package:hive_flutter/hive_flutter.dart';
import 'package:hive/hive.dart';
// 定义Hive适配器
part 'user_adapter.g.dart';
@HiveType(typeId: 0)
class HiveUser extends HiveObject {
@HiveField(0)
String name;
@HiveField(1)
String email;
@HiveField(2)
int age;
@HiveField(3)
DateTime createdAt;
HiveUser({
required this.name,
required this.email,
required this.age,
required this.createdAt,
});
}
class HiveDemo extends StatefulWidget {
@override
_HiveDemoState createState() => _HiveDemoState();
}
class _HiveDemoState extends State<HiveDemo> {
final TextEditingController _nameController = TextEditingController();
final TextEditingController _emailController = TextEditingController();
final TextEditingController _ageController = TextEditingController();
late Box<HiveUser> _userBox;
List<HiveUser> _users = [];
String _status = '';
@override
void initState() {
super.initState();
_initHive();
}
Future<void> _initHive() async {
await Hive.initFlutter();
// 注册适配器
Hive.registerAdapter(HiveUserAdapter());
// 打开盒子
_userBox = await Hive.openBox<HiveUser>('users');
_loadUsers();
}
void _loadUsers() {
final users = _userBox.values.toList();
setState(() {
_users = users;
});
}
Future<void> _addUser() async {
if (_nameController.text.isEmpty ||
_emailController.text.isEmpty ||
_ageController.text.isEmpty) {
setState(() {
_status = '请填写所有字段';
});
return;
}
try {
final user = HiveUser(
name: _nameController.text,
email: _emailController.text,
age: int.parse(_ageController.text),
createdAt: DateTime.now(),
);
await _userBox.add(user);
_nameController.clear();
_emailController.clear();
_ageController.clear();
_loadUsers();
setState(() {
_status = '用户添加成功';
});
} catch (e) {
setState(() {
_status = '添加失败: $e';
});
}
}
Future<void> _deleteUserAt(int index) async {
await _userBox.deleteAt(index);
_loadUsers();
setState(() {
_status = '用户删除成功';
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Hive数据库示例')),
body: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
children: [
Card(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
children: [
TextField(
controller: _nameController,
decoration: InputDecoration(labelText: '姓名'),
),
TextField(
controller: _emailController,
decoration: InputDecoration(labelText: '邮箱'),
),
TextField(
controller: _ageController,
decoration: InputDecoration(labelText: '年龄'),
keyboardType: TextInputType.number,
),
SizedBox(height: 10),
ElevatedButton(
onPressed: _addUser,
child: Text('添加用户'),
),
],
),
),
),
SizedBox(height: 16),
if (_status.isNotEmpty)
Card(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Text(_status),
),
),
SizedBox(height: 10),
Expanded(
child: _users.isEmpty
? Center(child: Text('暂无用户数据'))
: ListView.builder(
itemCount: _users.length,
itemBuilder: (context, index) {
final user = _users[index];
return Card(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
user.name,
style: Theme.of(context).textTheme.headlineSmall,
),
IconButton(
icon: Icon(Icons.delete, color: Colors.red),
onPressed: () => _deleteUserAt(index),
),
],
),
Text('邮箱: ${user.email}'),
Text('年龄: ${user.age}'),
Text('创建时间: ${user.createdAt}'),
],
),
),
);
},
),
),
],
),
),
);
}
@override
void dispose() {
Hive.close();
super.dispose();
}
}
Isar数据库
Isar是另一个高性能的NoSQL数据库,专为Flutter设计。
添加依赖
yaml
dependencies:
flutter:
sdk: flutter
isar: ^3.1.0+1
isar_flutter_libs: ^3.1.0+1
path_provider: ^2.1.1
Isar基础操作
dart
import 'package:isar/isar.dart';
import 'package:path_provider/path_provider.dart';
part 'user_isar.g.dart';
@Collection()
class IsarUser {
Id id = Isar.autoIncrement; // 您可以使用自动递增的ID
String name = '';
String email = '';
int age = 0;
DateTime createdAt = DateTime.now();
}
class IsarDemo extends StatefulWidget {
@override
_IsarDemoState createState() => _IsarDemoState();
}
class _IsarDemoState extends State<IsarDemo> {
late Future<Isar> _isar;
final TextEditingController _nameController = TextEditingController();
final TextEditingController _emailController = TextEditingController();
final TextEditingController _ageController = TextEditingController();
List<IsarUser> _users = [];
String _status = '';
@override
void initState() {
super.initState();
_initializeIsar();
}
Future<void> _initializeIsar() async {
final dir = await getApplicationDocumentsDirectory();
final isar = await Isar.open(
[IsarUserSchema],
directory: dir.path,
);
_isar = Future.value(isar);
_loadUsers();
}
Future<void> _loadUsers() async {
final isar = await _isar;
final users = await isar.isarUsers.where().findAll();
setState(() {
_users = users;
});
}
Future<void> _addUser() async {
if (_nameController.text.isEmpty ||
_emailController.text.isEmpty ||
_ageController.text.isEmpty) {
setState(() {
_status = '请填写所有字段';
});
return;
}
try {
final isar = await _isar;
final user = IsarUser()
..name = _nameController.text
..email = _emailController.text
..age = int.parse(_ageController.text)
..createdAt = DateTime.now();
await isar.writeTxn(() async {
await isar.isarUsers.put(user);
});
_nameController.clear();
_emailController.clear();
_ageController.clear();
await _loadUsers();
setState(() {
_status = '用户添加成功';
});
} catch (e) {
setState(() {
_status = '添加失败: $e';
});
}
}
Future<void> _deleteUser(Id id) async {
final isar = await _isar;
await isar.writeTxn(() async {
await isar.isarUsers.delete(id);
});
await _loadUsers();
setState(() {
_status = '用户删除成功';
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Isar数据库示例')),
body: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
children: [
Card(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
children: [
TextField(
controller: _nameController,
decoration: InputDecoration(labelText: '姓名'),
),
TextField(
controller: _emailController,
decoration: InputDecoration(labelText: '邮箱'),
),
TextField(
controller: _ageController,
decoration: InputDecoration(labelText: '年龄'),
keyboardType: TextInputType.number,
),
SizedBox(height: 10),
ElevatedButton(
onPressed: _addUser,
child: Text('添加用户'),
),
],
),
),
),
SizedBox(height: 16),
if (_status.isNotEmpty)
Card(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Text(_status),
),
),
SizedBox(height: 10),
Expanded(
child: FutureBuilder<Isar>(
future: _isar,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
}
return _users.isEmpty
? Center(child: Text('暂无用户数据'))
: ListView.builder(
itemCount: _users.length,
itemBuilder: (context, index) {
final user = _users[index];
return Card(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
user.name,
style: Theme.of(context).textTheme.headlineSmall,
),
IconButton(
icon: Icon(Icons.delete, color: Colors.red),
onPressed: () => _deleteUser(user.id),
),
],
),
Text('邮箱: ${user.email}'),
Text('年龄: ${user.age}'),
Text('创建时间: ${user.createdAt}'),
],
),
),
);
},
);
},
),
),
],
),
),
);
}
}
数据存储最佳实践
1. 选择合适的数据存储方式
dart
class StorageSelector {
/// 选择最适合的存储方式
static void selectStorageType() {
/*
SharedPreferences:
- 适用场景:用户偏好设置、应用配置、简单的标志位
- 限制:只能存储基本数据类型,不适合大量数据
文件存储:
- 适用场景:图片、文档、缓存文件、日志
- 优势:可存储任意数据,容量大
SQLite:
- 适用场景:结构化数据、需要复杂查询、关系型数据
- 优势:ACID特性,支持SQL查询
Hive/Isar:
- 适用场景:NoSQL数据、快速读写、对象存储
- 优势:性能高,使用简单
*/
}
}
2. 数据加密存储
dart
import 'dart:convert';
import 'package:crypto/crypto.dart';
import 'package:encrypt/encrypt.dart';
class SecureStorage {
static const String _key = 'your_secure_key_here'; // 实际应用中应更安全地管理密钥
// 加密数据
static String encryptData(String plainText) {
final key = Key.fromUtf8(_key.padRight(32).substring(0, 32)); // AES需要32字节密钥
final iv = IV.fromLength(16); // 初始化向量
final encrypter = Encrypter(AES(key));
final encrypted = encrypter.encrypt(plainText, iv: iv);
return encrypted.base64;
}
// 解密数据
static String decryptData(String encryptedText) {
final key = Key.fromUtf8(_key.padRight(32).substring(0, 32));
final iv = IV.fromLength(16);
final encrypter = Encrypter(AES(key));
final decrypted = encrypter.decrypt64(encryptedText, iv: iv);
return decrypted;
}
// 安全存储敏感信息
static Future<void> storeSensitiveData(String key, String data) async {
final encryptedData = encryptData(data);
final prefs = await SharedPreferences.getInstance();
await prefs.setString(key, encryptedData);
}
// 读取加密数据
static Future<String?> getSensitiveData(String key) async {
final prefs = await SharedPreferences.getInstance();
final encryptedData = prefs.getString(key);
if (encryptedData != null) {
return decryptData(encryptedData);
}
return null;
}
}
3. 数据备份和同步
dart
class DataBackupSync {
// 本地数据备份
static Future<void> backupUserData() async {
final prefs = await SharedPreferences.getInstance();
final dbPath = await getDatabasesPath();
// 备份SharedPreferences
final backupPrefs = await SharedPreferences.getInstance();
final keys = backupPrefs.getKeys();
final backupData = <String, dynamic>{};
for (final key in keys) {
final value = backupPrefs.get(key);
backupData[key] = value;
}
// 保存备份到文件
final directory = await getApplicationDocumentsDirectory();
final backupFile = File('${directory.path}/user_backup.json');
await backupFile.writeAsString(jsonEncode(backupData));
}
// 恢复用户数据
static Future<void> restoreUserData() async {
final directory = await getApplicationDocumentsDirectory();
final backupFile = File('${directory.path}/user_backup.json');
if (await backupFile.exists()) {
final backupContent = await backupFile.readAsString();
final backupData = jsonDecode(backupContent) as Map<String, dynamic>;
final prefs = await SharedPreferences.getInstance();
for (final entry in backupData.entries) {
final key = entry.key;
final value = entry.value;
if (value is String) {
await prefs.setString(key, value);
} else if (value is int) {
await prefs.setInt(key, value);
} else if (value is double) {
await prefs.setDouble(key, value);
} else if (value is bool) {
await prefs.setBool(key, value);
} else if (value is List) {
await prefs.setStringList(key, List<String>.from(value));
}
}
}
}
}
4. 存储空间管理
dart
class StorageManager {
// 检查可用存储空间
static Future<int> getAvailableStorage() async {
try {
final directory = await getApplicationDocumentsDirectory();
final stat = directory.statSync();
// 注意:在某些平台上无法直接获取可用空间
// 这里只是示例,实际实现可能需要额外的插件
return 0; // 返回可用空间(字节)
} catch (e) {
print('无法获取存储空间信息: $e');
return 0;
}
}
// 清理缓存文件
static Future<void> clearCache() async {
try {
final directory = await getTemporaryDirectory();
final cacheFiles = directory.listSync();
for (final file in cacheFiles) {
if (file is File) {
final modified = await file.lastModified();
final daysOld = DateTime.now().difference(modified).inDays;
// 删除超过7天的缓存文件
if (daysOld > 7) {
await file.delete();
}
}
}
} catch (e) {
print('清理缓存失败: $e');
}
}
// 获取存储使用情况
static Future<Map<String, int>> getStorageUsage() async {
try {
final appDir = await getApplicationDocumentsDirectory();
final tempDir = await getTemporaryDirectory();
int getAppDirSize(Directory dir) {
int total = 0;
final entities = dir.listSync(recursive: true);
for (final entity in entities) {
if (entity is File) {
total += entity.lengthSync();
}
}
return total;
}
return {
'app_documents': getAppDirSize(appDir),
'temp': getAppDirSize(tempDir),
};
} catch (e) {
print('获取存储使用情况失败: $e');
return {};
}
}
}
数据迁移策略
版本升级时的数据迁移
dart
class DataMigration {
static const String CURRENT_SCHEMA_VERSION_KEY = 'schema_version';
static const int CURRENT_VERSION = 2;
static Future<void> migrateIfNeeded() async {
final prefs = await SharedPreferences.getInstance();
final currentVersion = prefs.getInt(CURRENT_SCHEMA_VERSION_KEY) ?? 0;
if (currentVersion < 1) {
await _migrateFromVersion0To1();
}
if (currentVersion < 2) {
await _migrateFromVersion1To2();
}
// 更新版本号
await prefs.setInt(CURRENT_SCHEMA_VERSION_KEY, CURRENT_VERSION);
}
static Future<void> _migrateFromVersion0To1() async {
// 从版本0迁移到版本1的逻辑
print('执行从版本0到版本1的数据迁移');
// 例如:更改数据存储结构、转换数据格式等
}
static Future<void> _migrateFromVersion1To2() async {
// 从版本1迁移到版本2的逻辑
print('执行从版本1到版本2的数据迁移');
// 例如:新增表、修改字段等
}
}
总结
Flutter提供了多种数据存储方案,每种方案都有其适用场景:
- SharedPreferences:适合存储简单的键值对数据
- 文件存储:适合存储文件类型的数据
- SQLite:适合结构化数据和复杂查询
- Hive/Isar:适合高性能的NoSQL数据存储
选择合适的数据存储方案需要考虑以下因素:
- 数据类型和结构
- 数据量大小
- 查询复杂度
- 性能要求
- 安全性要求
- 数据持久化需求
在实际开发中,通常会结合多种存储方案来满足不同场景的需求。