【OpenHarmony】Flutter 本地存储全解析:从键值对到数据库

在 Flutter 应用开发中,本地存储是必不可少的功能。无论是保存用户登录信息、应用配置,还是存储结构化的业务数据,都需要选择合适的本地存储方案。Flutter 提供了多种本地存储方式,涵盖轻量级键值对存储、NoSQL 数据库和关系型数据库等,满足不同场景的需求。本文将详细解析 Flutter 中主流的本地存储方案,包括其特点、用法和适用场景。

一、Flutter 本地存储的常见场景与分类

Flutter 本地存储主要用于以下场景:

  • 保存轻量级配置信息(如主题模式、语言设置);
  • 缓存网络数据,减少重复请求;
  • 存储结构化业务数据(如本地订单、收藏列表);
  • 持久化用户登录状态、个人信息等。

根据存储数据的类型和结构,Flutter 本地存储可分为三类:

  1. 键值对存储 :适合存储简单的键值型数据,如SharedPreferencesHive(轻量 NoSQL,也支持键值对);
  2. NoSQL 数据库 :适合存储非结构化或半结构化数据,如HiveObjectBox
  3. 关系型数据库 :适合存储结构化、关联度高的数据,如SQFliteDrift

二、SharedPreferences:轻量级键值对存储

SharedPreferences是 Flutter 中最常用的轻量级存储方案,本质上是对 Android 的SharedPreferences和 iOS 的NSUserDefaults的封装,适用于存储简单的键值对数据(如字符串、数字、布尔值)。

1. 集成与基本使用

首先在pubspec.yaml中添加依赖:

复制代码
dependencies:
  shared_preferences: ^2.2.2

核心操作包括存、取、删、清

Dart 复制代码
import 'package:shared_preferences/shared_preferences.dart';

// 存储数据
Future<void> saveData() async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  await prefs.setString('username', 'FlutterDev'); // 存储字符串
  await prefs.setInt('age', 25); // 存储整数
  await prefs.setBool('isLogin', true); // 存储布尔值
  await prefs.setStringList('hobbies', ['coding', 'reading']); // 存储字符串列表
}

// 获取数据
Future<void> getData() async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  String? username = prefs.getString('username');
  int? age = prefs.getInt('age');
  bool? isLogin = prefs.getBool('isLogin');
  List<String>? hobbies = prefs.getStringList('hobbies');
  
  print("用户名:$username,年龄:$age,是否登录:$isLogin,爱好:$hobbies");
}

// 删除数据
Future<void> removeData() async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  await prefs.remove('username'); // 删除指定键的数据
}

// 清空所有数据
Future<void> clearData() async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  await prefs.clear();
}

2. 适用场景与局限性

适用场景 :存储应用配置、用户偏好设置、简单的状态标记(如是否首次启动)。局限性

  • 仅支持基本数据类型,无法存储复杂对象;
  • 存储容量有限,不适合存储大量数据;
  • 性能一般,频繁读写可能导致卡顿。

三、Hive:高性能 NoSQL 键值数据库

Hive是专为 Flutter 设计的轻量级 NoSQL 数据库,基于键值对存储,支持复杂对象序列化,性能远超SharedPreferences,且无需原生依赖,跨平台兼容性好。

1. 集成与初始化

添加依赖并配置:

Dart 复制代码
dependencies:
  hive: ^2.2.3
  hive_flutter: ^1.1.0

dev_dependencies:
  hive_generator: ^1.1.5
  build_runner: ^2.4.6

初始化 Hive:

Dart 复制代码
import 'package:hive_flutter/hive_flutter.dart';

void initHive() async {
  await Hive.initFlutter(); // 初始化Hive
  await Hive.openBox('userBox'); // 打开名为userBox的盒子(类似数据库表)
}

2. 基本操作

Hive 的核心操作围绕 Box(盒子) 展开,一个 Box 相当于一个数据集:

Dart 复制代码
// 存储数据
void saveToHive() {
  final box = Hive.box('userBox');
  box.put('user', {'name': 'FlutterDev', 'age': 25}); // 存储Map
  box.put('scores', [90, 85, 95]); // 存储列表
}

// 获取数据
void getFromHive() {
  final box = Hive.box('userBox');
  var user = box.get('user');
  var scores = box.get('scores');
  print("用户信息:$user,分数:$scores");
}

// 自定义对象存储(需序列化)
// 1. 创建实体类并添加注解
import 'package:hive/hive.dart';

part 'person.g.dart'; // 生成的序列化代码

@HiveType(typeId: 0)
class Person {
  @HiveField(0)
  final String name;

  @HiveField(1)
  final int age;

  Person({required this.name, required this.age});
}

// 2. 运行构建命令生成序列化代码:flutter pub run build_runner build

// 3. 注册适配器并存储对象
void saveCustomObject() async {
  Hive.registerAdapter(PersonAdapter()); // 注册适配器
  final box = Hive.box('userBox');
  box.put('person', Person(name: 'FlutterDev', age: 25));
  
  Person? person = box.get('person');
  print("自定义对象:${person?.name},${person?.age}");
}

3. 适用场景与优势

适用场景 :存储复杂对象、中等规模的本地数据、需要高性能读写的场景(如缓存列表数据)。优势

  • 支持复杂对象序列化,无需手动转换;
  • 纯 Dart 实现,跨平台无原生依赖;
  • 读写速度快,性能优于 SQFlite;
  • 支持加密存储,保护敏感数据。

四、SQFlite:SQLite 的 Flutter 封装

SQFlite是 Flutter 对 SQLite 数据库的封装,适用于存储结构化、关联度高的关系型数据,如电商订单、本地通讯录等。

1. 集成与数据库初始化

添加依赖:

bash 复制代码
dependencies:
  sqflite: ^2.3.0
  path: ^1.8.3

初始化数据库并创建表:

Dart 复制代码
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';

class DatabaseHelper {
  static final DatabaseHelper instance = DatabaseHelper._init();
  static Database? _database;

  DatabaseHelper._init();

  // 获取数据库实例
  Future<Database> get database async {
    if (_database != null) return _database!;
    _database = await _initDB('notes.db');
    return _database!;
  }

  // 初始化数据库
  Future<Database> _initDB(String filePath) async {
    final dbPath = await getDatabasesPath();
    final path = join(dbPath, filePath);

    return await openDatabase(path, version: 1, onCreate: _createDB);
  }

  // 创建表
  Future<void> _createDB(Database db, int version) async {
    await db.execute('''
      CREATE TABLE notes (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        title TEXT NOT NULL,
        content TEXT,
        create_time DATETIME DEFAULT CURRENT_TIMESTAMP
      )
    ''');
  }
}

2. CRUD 操作

Dart 复制代码
// 插入数据
Future<int> insertNote(Map<String, dynamic> note) async {
  final db = await DatabaseHelper.instance.database;
  return await db.insert('notes', note);
}

// 查询所有数据
Future<List<Map<String, dynamic>>> queryAllNotes() async {
  final db = await DatabaseHelper.instance.database;
  return await db.query('notes');
}

// 更新数据
Future<int> updateNote(Map<String, dynamic> note) async {
  final db = await DatabaseHelper.instance.database;
  int id = note['id'];
  return await db.update('notes', note, where: 'id = ?', whereArgs: [id]);
}

// 删除数据
Future<int> deleteNote(int id) async {
  final db = await DatabaseHelper.instance.database;
  return await db.delete('notes', where: 'id = ?', whereArgs: [id]);
}

3. 适用场景与局限性

适用场景 :存储结构化、有复杂关联关系的数据,如多表关联的业务数据。局限性

  • 需要编写 SQL 语句,学习成本较高;
  • 性能略低于 Hive,适合数据量中等的场景;
  • 跨平台需适配不同系统的 SQLite 版本。

五、Drift:类型安全的 SQL 数据库

Drift(原 Moor)是基于 SQLite 的高级封装,采用 Dart 代码生成的方式实现类型安全的数据库操作,无需手动编写 SQL 语句,开发效率更高。

1. 集成与基本使用

添加依赖:

Dart 复制代码
dependencies:
  drift: ^2.12.0
  sqlite3_flutter_libs: ^0.5.16
  path_provider: ^2.1.1
  path: ^1.8.3

dev_dependencies:
  drift_dev: ^2.12.0
  build_runner: ^2.4.6

定义数据库表和操作:

Dart 复制代码
import 'package:drift/drift.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
import 'package:drift/native.dart';
import 'dart:io';

// 定义表
class Notes extends Table {
  IntColumn get id => integer().autoIncrement()();
  TextColumn get title => text().notNull()();
  TextColumn get content => text().nullable()();
  DateTimeColumn get createTime => dateTime().withDefault(currentDateAndTime)();
}

// 定义数据库类
part 'database.g.dart';

@DriftDatabase(tables: [Notes])
class AppDatabase extends _$AppDatabase {
  AppDatabase() : super(_openConnection());

  @override
  int get schemaVersion => 1;

  // 插入笔记
  Future<int> insertNote(NotesCompanion note) => into(notes).insert(note);

  // 查询所有笔记
  Future<List<Note>> getAllNotes() => select(notes).get();

  // 更新笔记
  Future<int> updateNote(Note note) => update(notes).replace(note);

  // 删除笔记
  Future<int> deleteNote(Note note) => delete(notes).delete(note);
}

// 打开数据库连接
LazyDatabase _openConnection() {
  return LazyDatabase(() async {
    final dbFolder = await getApplicationDocumentsDirectory();
    final file = File(p.join(dbFolder.path, 'notes.db'));
    return NativeDatabase(file);
  });
}

运行构建命令生成代码:flutter pub run build_runner build,之后即可调用数据库方法:

Dart 复制代码
void testDrift() async {
  final db = AppDatabase();
  // 插入数据
  await db.insertNote(NotesCompanion(title: Value('Flutter笔记'), content: Value('Drift数据库学习')));
  // 查询数据
  List<Note> notes = await db.getAllNotes();
  print(notes);
}

2. 优势与适用场景

优势

  • 类型安全,编译期检查 SQL 错误;
  • 支持 Dart 语法代替 SQL 语句,开发更便捷;
  • 支持流查询(watch方法),数据变化时自动刷新 UI;
  • 兼容 SQLite 所有特性,支持复杂查询和事务。

适用场景:需要类型安全、复杂查询的关系型数据存储场景,适合中大型 Flutter 应用。

六、Flutter 本地存储方案的选择建议

  1. 简单键值对数据 :优先选择SharedPreferences,开发成本低;若需要存储复杂对象或追求高性能,选择Hive
  2. 非结构化 / 半结构化数据 :选择Hive,兼顾性能和易用性;
  3. 结构化、关联度高的数据
    • 若熟悉 SQL 且数据量较小,选择SQFlite
    • 若追求类型安全和开发效率,选择Drift
  4. 大数据量、高性能要求 :考虑ObjectBox(另一个高性能 NoSQL 数据库,适合海量数据存储)。

七、本地存储的注意事项

  1. 数据加密 :敏感数据(如用户密码、token)需加密存储,可使用encrypt包结合 Hive/SQFlite 实现;
  2. 数据清理:定期清理过期缓存数据,避免占用过多设备存储;
  3. 事务管理:批量操作数据时使用事务,确保数据一致性;
  4. 错误处理:捕获存储操作中的异常(如数据库打开失败、读写权限不足),避免程序崩溃;
  5. 适配不同平台:注意 Android 和 iOS 的存储路径、权限差异,确保跨平台兼容性。

八、总结

Flutter 提供了丰富的本地存储方案,从轻量级的SharedPreferences到高性能的Hive,再到关系型的SQFliteDrift,每种方案都有其适用场景。在实际开发中,需根据数据类型、规模和性能需求选择合适的存储方式,并遵循最佳实践确保数据安全和应用稳定性。掌握这些本地存储技术,能让 Flutter 应用在离线场景下也能提供流畅的用户体验。

相关推荐
一 乐1 小时前
购物商城|基于SprinBoot+vue的购物商城系统(源码+数据库+文档)
前端·javascript·数据库·vue.js·spring boot·后端
c***87191 小时前
【update 更新数据语法合集】.NET开源ORM框架 SqlSugar 系列
开源·.net
意疏1 小时前
openGauss 数据库快速上手评测:从 Docker 安装到SQL 实战
数据库·sql·docker
m0_598177231 小时前
SQL(一)
数据库·sql
z***94841 小时前
【MySQL】表空间丢失处理(Tablespace is missing for table 错误处理)
数据库·mysql
ShiMetaPi1 小时前
GM-3568JHF丨ARM+FPGA异构开发板系列教程:基础入门 05 软件更新
数据库·windows
小柯博客1 小时前
从零开始打造 OpenSTLinux 6.6 Yocto 系统 - STM32MP2(基于STM32CubeMX)(三)
stm32·嵌入式硬件·开源·嵌入式·yocto·st·stm32mp2
梁bk1 小时前
Redis 数据结构(下)ZSet, Hash
数据库·redis·缓存
☆光之梦☆1 小时前
《openGauss全密态与防篡改账本数据库:云上数据安全与可信的新范式》
数据库·python