Flutter本地存储完全指南

引言

本地存储是移动应用开发中不可或缺的一部分,它允许应用在设备上持久化保存数据。本文将深入探讨Flutter中的各种本地存储方案和最佳实践。

一、SharedPreferences

1.1 添加依赖

dependencies:
  shared_preferences: ^2.2.2

1.2 基本用法

import 'package:shared_preferences/shared_preferences.dart';

class PreferencesService {
  Future<void> saveString(String key, String value) async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setString(key, value);
  }

  Future<String?> getString(String key) async {
    final prefs = await SharedPreferences.getInstance();
    return prefs.getString(key);
  }

  Future<void> saveInt(String key, int value) async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setInt(key, value);
  }

  Future<int?> getInt(String key) async {
    final prefs = await SharedPreferences.getInstance();
    return prefs.getInt(key);
  }

  Future<void> saveBool(String key, bool value) async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setBool(key, value);
  }

  Future<bool?> getBool(String key) async {
    final prefs = await SharedPreferences.getInstance();
    return prefs.getBool(key);
  }

  Future<void> remove(String key) async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.remove(key);
  }

  Future<void> clear() async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.clear();
  }
}

1.3 实际应用

class AuthService {
  static const String _tokenKey = 'auth_token';
  static const String _userIdKey = 'user_id';

  Future<void> saveToken(String token) async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setString(_tokenKey, token);
  }

  Future<String?> getToken() async {
    final prefs = await SharedPreferences.getInstance();
    return prefs.getString(_tokenKey);
  }

  Future<void> saveUserId(String userId) async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setString(_userIdKey, userId);
  }

  Future<String?> getUserId() async {
    final prefs = await SharedPreferences.getInstance();
    return prefs.getString(_userIdKey);
  }

  Future<void> clearAuthData() async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.remove(_tokenKey);
    await prefs.remove(_userIdKey);
  }
}

二、Hive

2.1 添加依赖

dependencies:
  hive: ^2.2.3
  hive_flutter: ^1.1.0

dev_dependencies:
  hive_generator: ^1.1.5
  build_runner: ^2.4.6

2.2 初始化Hive

void main() async {
  await Hive.initFlutter();
  Hive.registerAdapter(UserAdapter());
  await Hive.openBox<User>('users');
  await Hive.openBox('settings');
  runApp(const MyApp());
}

2.3 创建Adapter

import 'package:hive/hive.dart';

part 'user.g.dart';

@HiveType(typeId: 0)
class User extends HiveObject {
  @HiveField(0)
  late String id;

  @HiveField(1)
  late String name;

  @HiveField(2)
  late String email;

  @HiveField(3)
  late int age;
}

2.4 生成Adapter

flutter pub run build_runner build

2.5 使用Hive

class UserRepository {
  final Box<User> _userBox;

  UserRepository(this._userBox);

  Future<void> saveUser(User user) async {
    await _userBox.put(user.id, user);
  }

  User? getUser(String id) {
    return _userBox.get(id);
  }

  List<User> getAllUsers() {
    return _userBox.values.toList();
  }

  Future<void> deleteUser(String id) async {
    await _userBox.delete(id);
  }
}

三、SQFlite

3.1 添加依赖

dependencies:
  sqflite: ^2.3.0
  path_provider: ^2.1.0

3.2 创建数据库

import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';

class DatabaseHelper {
  static Database? _database;

  Future<Database> get database async {
    if (_database != null) return _database!;
    
    _database = await _initDatabase();
    return _database!;
  }

  Future<Database> _initDatabase() async {
    final dbPath = await getDatabasesPath();
    final path = join(dbPath, 'example.db');

    return await openDatabase(
      path,
      version: 1,
      onCreate: (db, version) async {
        await db.execute('''
          CREATE TABLE users (
            id TEXT PRIMARY KEY,
            name TEXT,
            email TEXT,
            age INTEGER
          )
        ''');
      },
    );
  }

  Future<void> insertUser(User user) async {
    final db = await database;
    await db.insert(
      'users',
      user.toMap(),
      conflictAlgorithm: ConflictAlgorithm.replace,
    );
  }

  Future<User?> getUser(String id) async {
    final db = await database;
    final maps = await db.query(
      'users',
      where: 'id = ?',
      whereArgs: [id],
    );

    if (maps.isNotEmpty) {
      return User.fromMap(maps.first);
    }
    return null;
  }

  Future<List<User>> getAllUsers() async {
    final db = await database;
    final maps = await db.query('users');
    return maps.map((map) => User.fromMap(map)).toList();
  }

  Future<void> updateUser(User user) async {
    final db = await database;
    await db.update(
      'users',
      user.toMap(),
      where: 'id = ?',
      whereArgs: [user.id],
    );
  }

  Future<void> deleteUser(String id) async {
    final db = await database;
    await db.delete(
      'users',
      where: 'id = ?',
      whereArgs: [id],
    );
  }
}

3.3 User模型

class User {
  final String id;
  final String name;
  final String email;
  final int age;

  User({
    required this.id,
    required this.name,
    required this.email,
    required this.age,
  });

  Map<String, dynamic> toMap() {
    return {
      'id': id,
      'name': name,
      'email': email,
      'age': age,
    };
  }

  static User fromMap(Map<String, dynamic> map) {
    return User(
      id: map['id'],
      name: map['name'],
      email: map['email'],
      age: map['age'],
    );
  }
}

四、文件存储

4.1 添加依赖

dependencies:
  path_provider: ^2.1.0

4.2 文件操作

import 'dart:io';
import 'package:path_provider/path_provider.dart';

class FileStorageService {
  Future<String> get _localPath async {
    final directory = await getApplicationDocumentsDirectory();
    return directory.path;
  }

  Future<File> get _localFile async {
    final path = await _localPath;
    return File('$path/data.txt');
  }

  Future<String> readFile() async {
    try {
      final file = await _localFile;
      final contents = await file.readAsString();
      return contents;
    } catch (e) {
      return '';
    }
  }

  Future<File> writeFile(String content) async {
    final file = await _localFile;
    return file.writeAsString(content);
  }

  Future<File> appendToFile(String content) async {
    final file = await _localFile;
    return file.writeAsString(content, mode: FileMode.append);
  }

  Future<void> deleteFile() async {
    try {
      final file = await _localFile;
      if (await file.exists()) {
        await file.delete();
      }
    } catch (e) {
      // Handle error
    }
  }
}

4.3 保存JSON数据

import 'dart:convert';

class JsonStorageService {
  Future<void> saveJson(String key, dynamic data) async {
    final file = await _getJsonFile(key);
    final jsonString = jsonEncode(data);
    await file.writeAsString(jsonString);
  }

  Future<dynamic> loadJson(String key) async {
    try {
      final file = await _getJsonFile(key);
      final jsonString = await file.readAsString();
      return jsonDecode(jsonString);
    } catch (e) {
      return null;
    }
  }

  Future<File> _getJsonFile(String key) async {
    final path = await getApplicationDocumentsDirectory();
    return File('${path.path}/$key.json');
  }
}

五、存储方案对比

特性 SharedPreferences Hive SQFlite File
数据类型 基本类型 对象 关系型 任意
查询能力 中等
性能
适合场景 配置、token 复杂对象 大量数据 文件存储

六、最佳实践

6.1 选择合适的存储方案

// 简单配置 - SharedPreferences
final prefs = await SharedPreferences.getInstance();
await prefs.setString('theme', 'dark');

// 复杂对象 - Hive
final userBox = Hive.box<User>('users');
await userBox.put('1', User(id: '1', name: 'John'));

// 大量数据 - SQFlite
final db = await DatabaseHelper().database;
await db.insert('users', user.toMap());

6.2 错误处理

try {
  final prefs = await SharedPreferences.getInstance();
  await prefs.setString('key', 'value');
} catch (e) {
  // 处理存储错误
}

6.3 数据加密

// 使用encrypt包加密敏感数据
import 'package:encrypt/encrypt.dart';

class SecureStorage {
  final Encrypter _encrypter;
  final IV _iv;

  SecureStorage(this._encrypter, this._iv);

  String encrypt(String plainText) {
    return _encrypter.encrypt(plainText, iv: _iv).base64;
  }

  String decrypt(String encryptedText) {
    return _encrypter.decrypt64(encryptedText, iv: _iv);
  }
}

总结

选择合适的本地存储方案对于应用性能和用户体验至关重要:

  1. SharedPreferences:适合存储简单的配置和token
  2. Hive:适合存储复杂对象,性能优秀
  3. SQFlite:适合存储大量结构化数据
  4. File:适合存储文件和大型数据

通过合理选择存储方案,你可以构建高效、可靠的本地数据管理系统。

更多推荐