1166 字
6 分钟
开发 | Flutter本地数据持久化怎么选
2026-06-14 00:00:00

背景#

Flutter 应用只要不是纯展示页面,基本都会遇到本地数据持久化的问题。

比如:

  • 保存用户登录状态
  • 保存主题、语言、开关配置
  • 缓存接口返回的数据
  • 保存聊天记录、账单、笔记等业务数据
  • 离线时继续使用,联网后再同步

这些场景看起来都叫“保存到本地”,但实际适合的方案不一样。如果一开始选错了,后面很容易出现数据结构难维护、查询困难、迁移麻烦的问题。

常见方案#

Flutter 里常见的本地持久化方案大概有这几类:

方案适合场景不适合场景
shared_preferences少量配置、开关、token复杂业务数据
文件存储日志、缓存、导入导出文件频繁查询和更新
SQLite结构化数据、本地业务表简单配置项
Drift类型安全的 SQLite 封装很小的 demo
Hive/Isar本地对象存储、轻量缓存强关系型查询

我的习惯是先按照“数据复杂度”和“查询需求”来选。

shared_preferences#

shared_preferences 适合保存少量键值数据,比如主题、语言、是否首次启动。

final prefs = await SharedPreferences.getInstance();
await prefs.setBool('is_dark_mode', true);
await prefs.setString('token', 'xxx');
final isDarkMode = prefs.getBool('is_dark_mode') ?? false;
final token = prefs.getString('token');

它的优点是简单,缺点也很明显:不适合存复杂对象,更不适合存列表型业务数据。

比较适合保存:

  • theme_mode
  • locale
  • access_token
  • first_launch
  • last_login_user_id

不建议保存:

  • 聊天消息
  • 账单明细
  • 商品列表
  • 复杂用户资料

文件存储#

文件存储适合保存一些不需要复杂查询的内容,比如日志、图片缓存、导入导出的 JSON。

final directory = await getApplicationDocumentsDirectory();
final file = File('${directory.path}/notes.json');
await file.writeAsString(jsonEncode([
{'title': 'Flutter', 'content': 'local storage'},
]));
final content = await file.readAsString();
final data = jsonDecode(content);

这种方式直观,但问题是查询、更新、删除都要自己处理。数据少的时候没问题,数据一多就会变得很难维护。

如果数据本身天然就是文件,比如用户导出的备份、图片、日志,那文件存储很合适。如果是业务表数据,还是应该考虑数据库。

SQLite#

SQLite 适合保存结构化业务数据。

比如一个记账应用,账单记录就很适合放到 SQLite:

CREATE TABLE ledger_entries (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
amount REAL NOT NULL,
type TEXT NOT NULL,
created_at INTEGER NOT NULL
);

它的优点是:

  • 支持条件查询
  • 支持排序、分页
  • 支持事务
  • 支持索引
  • 数据结构清晰

缺点是直接写 SQL 会比较繁琐,字段改动后迁移也要自己处理。

Drift#

如果项目里本地数据比较重要,我更倾向于用 Drift。它本质上还是 SQLite,但提供了更好的类型安全和 Dart 层封装。

表定义大概是这样:

class LedgerEntries extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get title => text()();
RealColumn get amount => real()();
TextColumn get type => text()();
DateTimeColumn get createdAt => dateTime()();
}

查询可以写成:

Future<List<LedgerEntry>> getEntries() {
return (select(ledgerEntries)
..orderBy([
(table) => OrderingTerm.desc(table.createdAt),
]))
.get();
}

插入数据:

Future<int> insertEntry(LedgerEntriesCompanion entry) {
return into(ledgerEntries).insert(entry);
}

Drift 的好处是数据层更清楚,适合业务长期迭代。缺点是上手成本比 shared_preferences 高,也需要配置代码生成。

怎么选#

可以简单按这个规则判断:

需求推荐方案
保存几个配置项shared_preferences
保存 token、主题、语言shared_preferences
保存日志或导出文件文件存储
保存列表数据SQLite 或 Drift
需要条件查询、分页、排序SQLite 或 Drift
项目会长期维护Drift
只是快速 demoshared_preferences 或简单文件

还有一个比较实用的判断方法:如果你开始想给数据加 idcreatedAtupdatedAt,并且需要按条件查询,那基本就该用数据库了。

分层建议#

不要在页面里直接操作数据库。比较清晰的结构是:

presentation 页面和状态
domain 实体和业务接口
data 本地数据库、接口实现

页面只调用 repository:

final entries = await ledgerRepository.getEntries();

具体数据来自 SQLite、接口还是缓存,页面不用关心。

这样后面从本地数据切到服务端同步,也不会大面积改 UI。

小结#

Flutter 本地持久化不要只看“哪个库简单”,要先看数据类型。

我的选择习惯是:

  • 少量配置用 shared_preferences
  • 文件内容用文件存储
  • 业务数据用 SQLite
  • 长期维护的业务数据用 Drift

如果只是保存一个开关,用数据库会显得太重;如果已经是账单、聊天记录、笔记这类数据,还继续用 JSON 文件或键值存储,后面维护成本会越来越高。

开发 | Flutter本地数据持久化怎么选
https://fuwari.wisansiiz.top/posts/flutter-local-storage/
作者
Wisansiiz
发布于
2026-06-14
许可协议
CC BY-NC-SA 4.0