Flutter 本地存储方案:SharedPreferences、SQFlite 与 Hive
在 Flutter 应用开发中,本地存储是实现数据持久化的核心需求,广泛应用于保存用户配置、缓存网络数据、存储离线信息等场景。当前 Flutter 生态中,SharedPreferences、SQFlite、Hive 是最主流的三种本地存储方案,它们分别基于不同的存储原理,适配不同的数据规模与业务场景。本文将从核心原理、实战实现、优缺点分析、横向对比及选型建议五个维度,全面解析这三种方案,帮助开发者快速选择适配自身项目的本地存储方案。

作者:爱吃大芒果
个人主页 爱吃大芒果
本文所属专栏 Flutter
更多专栏
Ascend C 算子开发教程(进阶)
鸿蒙集成
从0到1自学C++
一、核心原理:三种方案的存储本质差异
本地存储的核心是将数据持久化到设备本地,三种方案的本质差异在于存储载体与数据结构,直接决定了其适用场景与性能表现。
1. SharedPreferences:键值对轻量存储
SharedPreferences 是基于平台原生键值对存储的封装:在 Android 端封装了 SharedPreferences,在 iOS 端封装了 NSUserDefaults。其核心特点是"轻量、简单",数据以键值对(Key-Value)形式存储,支持字符串、整数、布尔值、浮点数等基础数据类型,但不支持复杂对象直接存储。底层存储载体为 XML 文件(Android)或 plist 文件(iOS),适合存储少量简单数据。
2. SQFlite:本地关系型数据库
SQFlite 是 SQLite 数据库在 Flutter 中的封装,SQLite 是一款嵌入式关系型数据库,支持标准 SQL 语法。其核心特点是"结构化、支持复杂查询",数据存储在独立的数据库文件中,通过表结构定义数据格式,支持多表关联、事务、索引等关系型数据库特性。适合存储大量结构化数据,如用户列表、订单记录等。
3. Hive:NoSQL 文档型数据库
Hive 是专为 Flutter 设计的 NoSQL 文档型数据库,基于键值对存储,但支持复杂对象直接序列化存储。其核心特点是"高性能、跨平台、无依赖",底层采用二进制格式存储数据,无需额外的原生依赖(纯 Dart 实现),支持自定义对象存储(通过 TypeAdapter 实现序列化),同时提供了类似 SQL 的查询能力(如过滤、排序)。兼顾了 SharedPreferences 的简单性与 SQFlite 的数据管理能力,适合中大量复杂对象存储。
二、实战实现:同一需求的三种存储方式
以"存储用户信息(用户名、年龄、是否登录)"为实战需求,分别展示三种方案的实现流程与核心代码,直观感受其使用差异。
1. SharedPreferences 实现:轻量键值对存储
SharedPreferences 实现需经历"添加依赖→初始化→存储数据→读取数据→删除数据"五个步骤,核心代码如下:
(1)添加依赖
yaml
dependencies:
flutter:
sdk: flutter
shared_preferences: ^2.2.2 # 最新稳定版
(2)核心实现代码
dart
import 'package:shared_preferences/shared_preferences.dart';
// 封装 SharedPreferences 工具类
class SpUtil {
// 初始化 SharedPreferences(需在使用前调用)
static late SharedPreferences _prefs;
static Future<void> init() async {
_prefs = await SharedPreferences.getInstance();
}
// 存储用户信息(基础数据类型)
static Future<void> saveUserInfo({
required String username,
required int age,
required bool isLogin,
}) async {
await _prefs.setString('username', username);
await _prefs.setInt('age', age);
await _prefs.setBool('isLogin', isLogin);
}
// 读取用户信息
static Map<String, dynamic> getUserInfo() {
return {
'username': _prefs.getString('username') ?? '',
'age': _prefs.getInt('age') ?? 0,
'isLogin': _prefs.getBool('isLogin') ?? false,
};
}
// 删除单个用户信息
static Future<void> removeUserInfo(String key) async {
await _prefs.remove(key);
}
// 清空所有存储数据
static Future<void> clearAll() async {
await _prefs.clear();
}
}
// 调用示例
void main() async {
// 必须先初始化
await SpUtil.init();
// 存储用户信息
await SpUtil.saveUserInfo(
username: 'FlutterDeveloper',
age: 25,
isLogin: true,
);
// 读取用户信息
final userInfo = SpUtil.getUserInfo();
print('用户名:${userInfo['username']},年龄:${userInfo['age']},登录状态:${userInfo['isLogin']}');
// 删除单个数据
await SpUtil.removeUserInfo('age');
// 清空所有数据
// await SpUtil.clearAll();
}
核心特点:API 简洁直观,无需关注底层实现,适合存储少量基础类型数据。但不支持复杂对象直接存储,需手动将对象转换为基础类型(如 JSON 字符串)。
2. SQFlite 实现:结构化数据库存储
SQFlite 实现需经历"添加依赖→创建数据库与表→CRUD 操作→关闭数据库"五个步骤,核心代码如下:
(1)添加依赖
yaml
dependencies:
flutter:
sdk: flutter
sqflite: ^2.3.0 # 核心依赖
path: ^1.8.3 # 用于获取数据库文件路径
(2)核心实现代码
dart
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
// 定义用户模型
class User {
final String username;
final int age;
final bool isLogin;
User({
required this.username,
required this.age,
required this.isLogin,
});
// 转换为 Map(用于存储)
Map<String, dynamic> toMap() {
return {
'username': username,
'age': age,
'isLogin': isLogin ? 1 : 0, // SQLite 不支持布尔值,用 0/1 替代
};
}
// 从 Map 转换为 User(用于读取)
static User fromMap(Map<String, dynamic> map) {
return User(
username: map['username'],
age: map['age'],
isLogin: map['isLogin'] == 1,
);
}
}
// 封装 SQFlite 工具类
class DbUtil {
static late Database _database;
static const String dbName = 'user_db.db'; // 数据库名
static const String tableName = 'user'; // 表名
// 初始化数据库
static Future<void> init() async {
// 获取数据库存储路径
String dbPath = await getDatabasesPath();
String path = join(dbPath, dbName);
// 打开数据库(不存在则创建)
_database = await openDatabase(
path,
version: 1, // 数据库版本
onCreate: (db, version) {
// 创建表结构
db.execute('''
CREATE TABLE $tableName (
username TEXT PRIMARY KEY,
age INTEGER,
isLogin INTEGER
)
''');
},
);
}
// 插入用户信息(新增/更新)
static Future<void> insertUser(User user) async {
await _database.insert(
tableName,
user.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace, // 存在则替换
);
}
// 查询所有用户信息
static Future<List<User>> queryAllUsers() async {
final List<Map<String, dynamic>> maps = await _database.query(tableName);
return List.generate(maps.length, (i) => User.fromMap(maps[i]));
}
// 根据用户名查询用户
static Future<User?> queryUserByUsername(String username) async {
final List<Map<String, dynamic>> maps = await _database.query(
tableName,
where: 'username = ?',
whereArgs: [username], // 防止 SQL 注入
);
return maps.isNotEmpty ? User.fromMap(maps.first) : null;
}
// 删除用户
static Future<void> deleteUser(String username) async {
await _database.delete(
tableName,
where: 'username = ?',
whereArgs: [username],
);
}
// 关闭数据库
static Future<void> closeDb() async {
await _database.close();
}
}
// 调用示例
void main() async {
// 初始化数据库
await DbUtil.init();
// 插入用户信息
final user = User(
username: 'FlutterDeveloper',
age: 25,
isLogin: true,
);
await DbUtil.insertUser(user);
// 查询所有用户
final allUsers = await DbUtil.queryAllUsers();
print('所有用户:${allUsers.map((u) => u.username).toList()}');
// 根据用户名查询
final queryUser = await DbUtil.queryUserByUsername('FlutterDeveloper');
if (queryUser != null) {
print('查询用户:${queryUser.username},年龄:${queryUser.age}');
}
// 删除用户
await DbUtil.deleteUser('FlutterDeveloper');
// 关闭数据库(一般在应用退出时调用)
// await DbUtil.closeDb();
}
核心特点:支持结构化数据存储与复杂查询,适合大量数据管理。但需手动设计表结构,处理数据类型转换(如布尔值),SQL 语法有一定学习成本。
3. Hive 实现:高性能复杂对象存储
Hive 实现需经历"添加依赖→初始化→注册适配器→存储数据→读取数据"五个步骤,核心代码如下:
(1)添加依赖
yaml
dependencies:
flutter:
sdk: flutter
hive: ^2.2.3 # 核心依赖
hive_flutter: ^1.1.0 # Flutter 适配依赖(提供路径管理等)
dev_dependencies:
hive_generator: ^1.1.5 # 代码生成工具
build_runner: ^2.4.4 # 代码生成工具
(2)核心实现代码
dart
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
// 1. 定义用户模型(添加 @HiveType 注解)
part 'user.g.dart'; // 生成的适配器文件
@HiveType(typeId: 0) // typeId 为唯一标识(0-223)
class User {
@HiveField(0) // 字段标识(唯一)
final String username;
@HiveField(1)
final int age;
@HiveField(2)
final bool isLogin;
User({
required this.username,
required this.age,
required this.isLogin,
});
}
// 2. 生成适配器(执行命令:flutter pub run build_runner build)
// 生成后会自动创建 user.g.dart 文件
// 3. 封装 Hive 工具类
class HiveUtil {
static late Box<User> _userBox;
static const String boxName = 'user_box'; // 盒子名(Hive 中数据存储在盒子里)
// 初始化 Hive
static Future<void> init() async {
await Hive.initFlutter(); // 初始化 Flutter 适配
Hive.registerAdapter(UserAdapter()); // 注册适配器(必须)
_userBox = await Hive.openBox<User>(boxName); // 打开盒子
}
// 存储用户信息(key 为用户名,value 为 User 对象)
static void putUser(String key, User user) {
_userBox.put(key, user);
}
// 根据 key 读取用户信息
static User? getUser(String key) {
return _userBox.get(key);
}
// 读取所有用户信息
static Map<String, User> getAllUsers() {
return _userBox.toMap().cast<String, User>();
}
// 删除用户信息
static void deleteUser(String key) {
_userBox.delete(key);
}
// 清空盒子
static Future<void> clearBox() async {
await _userBox.clear();
}
// 关闭 Hive
static Future<void> closeHive() async {
await Hive.close();
}
}
// 调用示例
void main() async {
// 初始化 Hive
await HiveUtil.init();
// 存储用户信息
final user = User(
username: 'FlutterDeveloper',
age: 25,
isLogin: true,
);
HiveUtil.putUser('FlutterDeveloper', user);
// 读取用户信息
final queryUser = HiveUtil.getUser('FlutterDeveloper');
if (queryUser != null) {
print('用户名:${queryUser.username},年龄:${queryUser.age},登录状态:${queryUser.isLogin}');
}
// 读取所有用户
final allUsers = HiveUtil.getAllUsers();
print('所有用户:${allUsers.keys.toList()}');
// 删除用户
HiveUtil.deleteUser('FlutterDeveloper');
// 清空盒子
// await HiveUtil.clearBox();
// 关闭 Hive
// await HiveUtil.closeHive();
}
核心特点:支持复杂对象直接存储(无需手动转换),API 简洁,性能优异,纯 Dart 实现无原生依赖。需通过代码生成工具创建适配器,适配复杂对象存储。
三、优缺点深度分析:适配场景决定选型
结合实战体验,从数据类型、性能、易用性、扩展性等维度,深度剖析三种方案的优缺点,明确其适用边界。
1. SharedPreferences 优缺点
优点 :① 易用性极高,API 简洁直观,开发成本低;② 轻量级,无额外依赖,集成简单;③ 跨平台适配良好,底层基于原生实现,稳定性高;④ 适合存储少量配置信息(如登录状态、主题设置)。
缺点:① 仅支持基础数据类型,不支持复杂对象直接存储;② 性能较差,大量数据存储时读取速度慢;③ 无事务支持,数据一致性难以保证;④ 不支持复杂查询,仅能通过键获取值。
2. SQFlite 优缺点
优点 :① 支持结构化数据存储,表结构清晰,适合大量数据管理;② 支持标准 SQL 语法,可实现复杂查询(多条件过滤、排序、关联查询等);③ 支持事务,保证数据一致性;④ 稳定性高,适配所有 Flutter 支持的平台。
缺点:① 易用性较差,需手动设计表结构、处理数据类型转换;② SQL 语法有一定学习成本,开发效率低;③ 复杂对象存储需手动序列化/反序列化;④ 性能一般,大量数据读写时效率低于 Hive。
3. Hive 优缺点
优点 :① 性能优异,底层二进制存储,读写速度快于 SQFlite;② 支持复杂对象直接存储,通过适配器实现自动化序列化;③ 纯 Dart 实现,无原生依赖,跨平台适配更简单;④ API 简洁直观,兼顾易用性与扩展性;⑤ 支持事务、索引、查询过滤等高级特性。
缺点:① 复杂对象存储需通过代码生成工具创建适配器,额外增加配置步骤;② 生态相对 SQFlite 较新,部分边缘场景支持不足;③ 不支持 SQL 语法,复杂查询需通过 Hive 自带 API 实现,灵活性低于 SQFlite。
四、横向对比:一张表看懂核心差异
| 对比维度 | SharedPreferences | SQFlite | Hive |
|---|---|---|---|
| 存储类型 | 键值对(基础类型) | 关系型数据库(结构化) | NoSQL 文档型(键值对+复杂对象) |
| 支持数据类型 | 字符串、整数、布尔值、浮点数、列表 | 文本、整数、浮点数、 blob 等(需手动转换布尔值) | 所有 Dart 基础类型+自定义对象 |
| 易用性 | ★★★★★(极高) | ★★☆(较低) | ★★★★(较高) |
| 性能(大量数据) | ★☆(较差) | ★★★(一般) | ★★★★★(极佳) |
| 复杂查询支持 | 无 | ★★★★★(SQL 语法,灵活) | ★★★(自带 API,有限灵活) |
| 事务支持 | 无 | 有 | 有 |
| 跨平台依赖 | 依赖原生实现 | 依赖原生 SQLite | 纯 Dart,无依赖 |
| 适用数据规模 | 少量(KB 级) | 大量(MB/GB 级) | 中大量(MB 级) |
| 扩展能力 | 差 | 强(SQL 扩展) | 强(自定义适配器) |
五、实战选型建议:匹配项目与业务需求
本地存储方案的选型需结合数据规模、数据类型、查询需求、开发效率四大核心因素,以下是针对性建议:
1. 优先选 SharedPreferences 的场景
① 存储少量配置信息(如登录状态、主题模式、语言设置、用户 Token);② 数据类型简单(仅基础类型),无需复杂查询;③ 追求极致开发效率,无需额外配置;④ 小型工具类 App 或 MVP 原型验证。
2. 优先选 SQFlite 的场景
① 存储大量结构化数据(如用户列表、订单记录、离线缓存的商品数据);② 需要复杂查询(如多条件过滤、排序、分组、多表关联);③ 对数据一致性要求高,需要事务支持;④ 团队熟悉 SQL 语法,可接受较高的开发成本。
3. 优先选 Hive 的场景
① 存储中大量复杂对象(如自定义模型、嵌套数据结构);② 追求高性能读写,对响应速度要求高;③ 跨平台适配需求严格(如需要适配 Web 端,避免原生依赖);④ 兼顾易用性与扩展性,既不想写 SQL,又需要比 SharedPreferences 更强的功能。
4. 混合使用建议
大型项目可采用"主方案+辅助方案"的混合模式:① 用 SharedPreferences 存储配置信息(如登录状态、Token);② 用 SQFlite 或 Hive 存储核心业务数据(如用户信息、订单列表)。例如:电商 App 中,用 SharedPreferences 保存用户登录状态,用 Hive 存储离线商品缓存,用 SQFlite 存储复杂的订单历史数据。
六、注意事项与最佳实践
无论选择哪种存储方案,都需注意以下核心要点,提升数据存储的稳定性与安全性:
-
数据加密:敏感数据(如用户密码、Token)需加密后存储,可使用
encrypt库实现 AES 加密; -
初始化时机:所有存储方案的初始化都需在异步中完成,建议在
main函数中初始化,确保使用前已完成; -
资源释放:SQFlite 与 Hive 需在应用退出时关闭,避免资源泄漏;
-
数据迁移:SQFlite 需妥善处理数据库版本升级与表结构迁移,Hive 需处理适配器版本兼容;
-
性能优化:① SharedPreferences 避免频繁读写大量数据;② SQFlite 合理创建索引提升查询速度;③ Hive 避免在主线程进行大量数据读写,可使用
compute进行异步处理。
七、结语
SharedPreferences、SQFlite、Hive 三种本地存储方案无绝对优劣,核心差异在于适配场景:SharedPreferences 胜在"简单、轻量",适合少量配置;SQFlite 胜在"结构化、强查询",适合大量复杂数据;Hive 胜在"高性能、跨平台、支持复杂对象",兼顾易用性与扩展性。
开发者在选型时,应跳出"技术优劣"的误区,聚焦业务需求:明确数据规模、数据类型、查询复杂度,结合团队技术栈选择最能降低开发成本、提升应用性能的方案。同时,合理运用混合存储模式,可最大化发挥各方案的优势,构建稳定、高效的本地存储体系。