在 Flutter 开发中,本地持久化存储直接影响应用运行性能、开发效率与用户体验 。目前业内最常用的三种方案分别是轻量键值库 SharedPreferences、高性能 NoSQL 数据库 Hive、传统关系型数据库 SQLite(sqflite)。本文会结合使用场景、依赖配置、完整代码、核心特性逐一拆解,并附上选型对照表,帮助你根据业务需求精准选择存储方案。
一、SharedPreferences:轻量级键值存储(基础配置首选)
1. 核心定位与适用场景
SharedPreferences 是 Flutter 官方推荐的轻量键值对存储 ,底层封装了 Android 原生 SharedPreferences 和 iOS 原生 NSUserDefaults,仅支持字符串、数字、布尔值等基础数据类型。
- ✅ 最佳场景:App 全局配置、主题模式、语言设置、登录状态、功能开关、首次启动标记等小型简单数据。
- ❌ 不适用:大量列表数据、自定义对象、复杂业务数据、高频读写场景。
2. 依赖引入
在项目根目录 pubspec.yaml 中添加依赖,当前稳定版本 2.3.0:
yaml
yaml
dependencies:
flutter:
sdk: flutter
shared_preferences: ^2.3.0
执行 flutter pub get 完成安装。
3. 完整代码实战(封装工具类)
推荐封装统一工具类,避免重复初始化实例,简化全局调用。示例以主题配置为例,同时拓展增、删、查基础操作:
dart
csharp
import 'package:shared_preferences/shared_preferences.dart';
/// 本地配置管理工具类
class SettingsService {
// 定义存储键名(统一管理,避免硬编码)
static const String _themeKey = "theme_mode";
static const String _loginKey = "is_login";
/// 保存主题模式
Future<void> saveTheme(String theme) async {
// 获取 SharedPreferences 单例实例
final prefs = await SharedPreferences.getInstance();
// 写入字符串数据
await prefs.setString(_themeKey, theme);
}
/// 读取主题模式(设置默认值为系统跟随)
Future<String> getTheme() async {
final prefs = await SharedPreferences.getInstance();
// 取值,为空时返回默认值
return prefs.getString(_themeKey) ?? "system";
}
/// 保存登录状态(布尔值)
Future<void> setLoginStatus(bool isLogin) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool(_loginKey, isLogin);
}
/// 读取登录状态
Future<bool> getLoginStatus() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getBool(_loginKey) ?? false;
}
/// 删除指定配置
Future<void> deleteTheme() async {
final prefs = await SharedPreferences.getInstance();
await prefs.remove(_themeKey);
}
/// 清空所有本地配置
Future<void> clearAllSettings() async {
final prefs = await SharedPreferences.getInstance();
await prefs.clear();
}
}
4. 页面调用示例
dart
csharp
// 异步读取主题
void loadTheme() async {
String theme = await SettingsService().getTheme();
print("当前主题:$theme");
}
// 切换为深色主题
void switchDarkTheme() async {
await SettingsService().saveTheme("dark");
}
5. 优缺点总结
- 优点:接入零成本、API 极简、跨平台兼容、原生系统适配完善。
- 缺点:仅支持基础数据类型、大数据读写性能差、无加密能力、不支持复杂查询。
二、Hive:高性能 NoSQL 数据库(结构化对象 / 离线缓存首选)
1. 核心定位与适用场景
Hive 是一款纯 Dart 编写的高性能本地 NoSQL 数据库 ,无需原生桥接,读写速度远超 SharedPreferences 和 SQLite,原生支持自定义 Dart 对象,搭配 TypeAdapter 实现类型安全,还支持数据加密。
- ✅ 最佳场景:离线数据缓存、任务列表、笔记、商品列表等结构化对象数据、中大型数据集;需要数据实时响应 UI 更新的场景。
- ❌ 不适用:需要多表关联、复杂 SQL 聚合查询的关系型业务。
2. 依赖引入
Hive 分为运行依赖和编译依赖(代码生成器),pubspec.yaml 配置如下:
yaml
yaml
dependencies:
flutter:
sdk: flutter
hive: ^2.2.3 # Hive 核心库
hive_flutter: ^1.1.0 # Flutter 适配插件
dev_dependencies:
hive_generator: ^2.0.1 # 代码生成器(生成对象适配器)
build_runner: ^2.4.0 # Dart 构建工具
执行 flutter pub get 安装依赖。
3. 分步实战(模型定义 → 初始化 → CRUD → 响应式 UI)
步骤 1:定义实体模型(Hive 对象)
以任务 Task 模型为例,使用注解标记字段,用于自动生成适配器:
dart
dart
import 'package:hive/hive.dart';
/// 任务实体类,typeId 全局唯一(0~255)
@HiveType(typeId: 0)
class Task extends HiveObject {
/// 任务唯一ID
@HiveField(0)
late String id;
/// 任务标题
@HiveField(1)
late String title;
/// 任务完成状态
@HiveField(2)
late bool isDone;
/// 创建时间
@HiveField(3)
late DateTime createdAt;
// 构造方法
Task({
required this.id,
required this.title,
required this.isDone,
required this.createdAt,
});
}
步骤 2:生成 TypeAdapter(核心步骤)
打开终端,在项目根目录执行命令,自动生成 TaskAdapter 适配器:
bash
运行
arduino
dart run build_runner build
执行成功后,会在当前目录生成 task.g.dart 文件,必须在模型文件中引入:
dart
dart
part 'task.g.dart'; // 追加在 Task 类文件末尾
步骤 3:全局初始化 Hive
在 main.dart 的 main 函数中完成初始化(全局仅执行一次):
dart
scala
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'task.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// 初始化 Hive(适配 Flutter 路径)
await Hive.initFlutter();
// 注册自定义对象适配器
Hive.registerAdapter(TaskAdapter());
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(home: TaskListPage());
}
}
步骤 4:封装 CRUD 工具类
对 Hive 的 Box(数据容器)进行封装,实现增、查、改、删全操作:
dart
rust
import 'package:hive/hive.dart';
import 'task.dart';
class HiveTaskService {
// 定义 Box 名称(数据容器)
static const String _taskBoxName = "tasks";
/// 获取任务 Box 实例
static Future<Box<Task>> getTaskBox() async {
return await Hive.openBox<Task>(_taskBoxName);
}
/// 新增/更新任务(key 为任务ID,存在则覆盖)
static Future<void> saveTask(Task task) async {
final box = await getTaskBox();
await box.put(task.id, task);
}
/// 查询所有任务
static Future<List<Task>> getAllTasks() async {
final box = await getTaskBox();
return box.values.toList();
}
/// 根据ID删除任务
static Future<void> deleteTask(String taskId) async {
final box = await getTaskBox();
await box.delete(taskId);
}
/// 清空所有任务
static Future<void> clearAllTasks() async {
final box = await getTaskBox();
await box.clear();
}
}
步骤 5:响应式 UI(数据变化自动刷新)
Hive 原生支持监听 Box 数据变化,搭配 ValueListenableBuilder 实现无状态刷新 ,无需手动调用 setState:
dart
less
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'task.dart';
import 'hive_task_service.dart';
class TaskListPage extends StatelessWidget {
const TaskListPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("Hive 任务列表")),
body: ValueListenableBuilder<Box<Task>>(
// 监听 tasks 容器数据变化
valueListenable: Hive.box<Task>("tasks").listenable(),
builder: (context, box, child) {
// 实时获取最新任务列表
List<Task> taskList = box.values.toList();
if (taskList.isEmpty) {
return const Center(child: Text("暂无任务"));
}
// 列表渲染
return ListView.builder(
itemCount: taskList.length,
itemBuilder: (context, index) {
Task task = taskList[index];
return ListTile(
title: Text(
task.title,
style: TextStyle(
decoration: task.isDone
? TextDecoration.lineThrough
: null,
),
),
subtitle: Text("创建时间:${task.createdAt.toLocal().toString().split(".")[0]}"),
trailing: IconButton(
icon: const Icon(Icons.delete, color: Colors.red),
onPressed: () => HiveTaskService.deleteTask(task.id),
),
);
},
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// 模拟新增任务
Task newTask = Task(
id: DateTime.now().millisecondsSinceEpoch.toString(),
title: "新任务 ${DateTime.now().hour}:${DateTime.now.minute}",
isDone: false,
createdAt: DateTime.now(),
);
HiveTaskService.saveTask(newTask);
},
child: const Icon(Icons.add),
),
);
}
}
4. 进阶特性与补充
- 数据加密 :Hive 支持 AES 加密,适合存储隐私数据,搭配
hive_encryption插件即可实现; - 多 Box 隔离 :不同业务数据拆分到不同
Box,提升读写效率; - 优点:性能极强、原生支持对象存储、类型安全、响应式 UI、跨平台完美兼容;
- 缺点:不支持 SQL 语句、无表关联能力,复杂关系数据场景受限。
三、SQLite(sqflite):关系型数据库(复杂查询 / 多表关联首选)
1. 核心定位与适用场景
sqflite 是 Flutter 生态中使用最广泛的 SQLite 封装库,标准关系型数据库,支持完整 SQL 语法、多表关联(JOIN)、聚合查询、事务、索引等数据库能力。
- ✅ 最佳场景:需要复杂筛选、联表查询、数据统计、事务保证的关系型结构化数据,如订单系统、通讯录、本地账单等。
- ❌ 不适用:简单配置、纯对象缓存(开发成本高)。
2. 依赖引入
yaml
yaml
dependencies:
flutter:
sdk: flutter
sqflite: ^2.3.0 # SQLite 核心库
path_provider: ^2.1.2 # 获取本地存储路径
path: ^1.8.3 # 路径拼接工具
执行 flutter pub get 安装。
3. 完整代码实战(数据库初始化 + 表创建 + CRUD)
采用单例模式封装数据库工具类,避免重复创建数据库实例,保证全局唯一连接。
dart
dart
import 'dart:io';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';
/// SQLite 数据库工具类
class DatabaseHelper {
// 数据库单例
static Database? _database;
/// 全局获取数据库实例
static Future<Database> get database async {
if (_database != null) return _database!;
// 初始化数据库
_database = await _initDatabase();
return _database!;
}
/// 初始化数据库(指定路径 + 创建表)
static Future<Database> _initDatabase() async {
// 1. 获取应用私有数据库目录
Directory appDir = await getApplicationDocumentsDirectory();
// 2. 拼接数据库完整路径(文件名为 app.db)
String dbPath = join(appDir.path, "app.db");
// 3. 打开/创建数据库,版本号用于数据库升级
return await openDatabase(
dbPath,
version: 1,
// 数据库首次创建时执行(建表语句)
onCreate: (Database db, int version) async {
// 创建任务表:id(主键)、title(标题)、is_done(完成状态)、created_at(创建时间)
await db.execute('''
CREATE TABLE tasks (
id TEXT PRIMARY KEY,
title TEXT NOT NULL,
is_done INTEGER DEFAULT 0,
created_at TEXT NOT NULL
)
''');
},
);
}
/// 新增/更新任务(冲突时覆盖原有数据)
static Future<void> insertTask(Map<String, dynamic> task) async {
final db = await database;
await db.insert(
"tasks",
task,
conflictAlgorithm: ConflictAlgorithm.replace, // 主键冲突则替换
);
}
/// 查询所有任务(按创建时间倒序)
static Future<List<Map<String, dynamic>>> getAllTasks() async {
final db = await database;
// 原生 SQL 查询,支持排序、条件筛选
return await db.query(
"tasks",
orderBy: "created_at DESC",
);
}
/// 根据ID删除任务
static Future<void> deleteTask(String taskId) async {
final db = await database;
await db.delete(
"tasks",
where: "id = ?", // 占位符,防止SQL注入
whereArgs: [taskId],
);
}
/// 清空任务表
static Future<void> clearTable() async {
final db = await database;
await db.delete("tasks");
}
}
4. 页面调用示例
dart
dart
import 'package:flutter/material.dart';
import 'database_helper.dart';
class SqliteTaskPage extends StatefulWidget {
const SqliteTaskPage({super.key});
@override
State<SqliteTaskPage> createState() => _SqliteTaskPageState();
}
class _SqliteTaskPageState extends State<SqliteTaskPage> {
List<Map<String, dynamic>> _taskList = [];
// 页面加载时查询数据
@override
void initState() {
super.initState();
_loadTasks();
}
/// 加载所有任务
Future<void> _loadTasks() async {
List<Map<String, dynamic>> list = await DatabaseHelper.getAllTasks();
setState(() {
_taskList = list;
});
}
/// 新增任务
Future<void> _addTask() async {
String taskId = DateTime.now().millisecondsSinceEpoch.toString();
Map<String, dynamic> newTask = {
"id": taskId,
"title": "SQLite 新任务",
"is_done": 0, // SQLite 无布尔值,用 0(false)/1(true) 替代
"created_at": DateTime.now().toIso8601String(),
};
await DatabaseHelper.insertTask(newTask);
_loadTasks(); // 刷新列表
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("SQLite 任务列表")),
body: _taskList.isEmpty
? const Center(child: Text("暂无任务"))
: ListView.builder(
itemCount: _taskList.length,
itemBuilder: (context, index) {
var task = _taskList[index];
return ListTile(
title: Text(task["title"]),
trailing: IconButton(
icon: const Icon(Icons.delete, color: Colors.red),
onPressed: () async {
await DatabaseHelper.deleteTask(task["id"]);
_loadTasks();
},
),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: _addTask,
child: const Icon(Icons.add),
),
);
}
}
5. 补充说明
- 数据类型限制 :SQLite 原生无布尔类型,使用
0代表 false、1代表 true;时间推荐转为字符串存储; - 数据库升级 :修改
version版本号,配合onUpgrade回调实现表结构升级; - 加密方案 :如需加密,可使用
sqlcipher_flutter_libs替换原生 SQLite; - 优点:功能完备、支持复杂 SQL、事务、索引、多表关联,适合企业级复杂业务;
- 缺点:学习成本高、代码冗余、简单场景下性能不如 Hive。
四、三大存储方案综合选型对照表
结合业务场景、性能、开发成本整理核心选型规则,直接对照选择即可:
表格
| 业务使用场景 | 最优存储方案 | 补充说明 |
|---|---|---|
| App 配置、主题、语言、登录状态、功能开关 | SharedPreferences | 极简开发,仅存少量基础类型数据 |
| 离线缓存、任务 / 笔记 / 商品列表、自定义对象、响应式 UI | Hive | 高性能、无需手动序列化,优先推荐 |
| 多表关联、复杂筛选、数据统计、事务操作、关系型数据 | SQLite(sqflite) | 依赖 SQL 能力,复杂业务必备 |
| 本地数据需要加密保护 | Hive (AES 加密) / SQLCipher | 敏感数据专用加密方案 |
五、总结
- 小型配置优先 SharedPreferences:一行代码即可完成读写,是 Flutter 配置存储的标配;
- 对象 / 列表缓存优先 Hive:兼顾性能与开发效率,绝大多数离线存储场景的最优解,也是目前社区主流推荐方案;
- 复杂关系数据必选 SQLite:当业务出现多表、联表、复杂查询时,关系型数据库的优势无可替代。
实际项目中也可组合使用:例如用 SharedPreferences 存储用户主题配置,Hive 缓存首页列表数据,SQLite 管理订单等复杂关系数据,充分发挥各方案的优势。