Skip to content
On this page

Flutter数据存储

在移动应用开发中,数据存储是至关重要的功能。Flutter提供了多种数据存储方案,从简单的键值对存储到复杂的数据库系统。本章将详细介绍Flutter中的各种数据存储方式及其适用场景。

本地存储概述

Flutter中的数据存储主要分为以下几类:

  1. 键值对存储:适用于存储简单的配置数据
  2. 文件存储:适用于存储文件类型的大量数据
  3. 数据库存储:适用于结构化数据的存储和查询
  4. 缓存存储:适用于临时数据的快速读写

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提供了多种数据存储方案,每种方案都有其适用场景:

  1. SharedPreferences:适合存储简单的键值对数据
  2. 文件存储:适合存储文件类型的数据
  3. SQLite:适合结构化数据和复杂查询
  4. Hive/Isar:适合高性能的NoSQL数据存储

选择合适的数据存储方案需要考虑以下因素:

  • 数据类型和结构
  • 数据量大小
  • 查询复杂度
  • 性能要求
  • 安全性要求
  • 数据持久化需求

在实际开发中,通常会结合多种存储方案来满足不同场景的需求。