懂 Vue、React 就懂 Flutter 数据存储

在Flutter的世界里,有三个特别的储物柜:SharedPreferences、SQLite数据库和文件存储。SharedPreferences像是你的随身小本子,你可以在其中记下一些键值对,比如你的喜好设置,它非常轻便,适合存储少量的数据。SQLite数据库就像是你的大书柜,你可以在其中存储大量的数据并进行复杂查询,它将信息安排得井井有条。而文件存储就像你的仓库,你可以在其中存储大量的数据,如图片或视频。这其实和前端存储很类似,在浏览器中,少量数据数据我们可以存在LocalStorage中, 大量数据可以存在IndexedDB。

SharedPreferences

SharedPreferences 与 Web 的 LocalStorage 类似,都是以键值对的形式存储数据。这使得前端开发者可以更方便地理解和使用Flutter的数据存储。

例如,如果你正在开发一个音乐播放器应用,你可能需要存储用户的播放设置,比如播放模式(顺序播放、随机播放等)、音量大小等。在这种情况下,你可以使用SharedPreferences来存储这些用户偏好。

首先,获取 SharedPreferences 的实例,然后使用 putString 和 putFloat 方法来存储数据,如下所示:

dart 复制代码
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString('play_mode', 'random');
prefs.setFloat('volume', 0.7);

在这个例子中,play_modevolume 都是键,random0.7 分别是要存储的值,表示播放模式和音量大小。当你需要获取这个值时,可以使用 getStringgetFloat 方法,如下所示:

dart 复制代码
SharedPreferences prefs = await SharedPreferences.getInstance();
String playMode = prefs.getString('play_mode');
float volume = prefs.getFloat('volume');

请注意,使用时我们需要安装依赖 shared_preferences

sh 复制代码
flutter pub add shared_preferences

虽然SharedPreferences和LocalStorage在功能上相似,但SharedPreferences在数据类型的支持上更为丰富。SharedPreferences可以存储的数据类型包括字符串、整数、布尔值和浮点数。而LocalStorage主要存储的是字符串类型的数据。如果你尝试在 LocalStorage 中存储非字符串类型的数据,如数字或对象,它会被自动转换为字符串,可能很多人都遇到过这个 Bug

sh 复制代码
localStorage.setItem("data", {hello: world})
localStorage.getItem("data")
'[object Object]'

SQLite

对于更复杂的数据存储需求,如需要存储大量数据或需要进行复杂查询的情况,开发者则可能会选择数据库存储。Flutter支持SQLite数据库,开发者可以使用SQLite进行本地数据的存储。

同样的,我们需要先添加依赖

dart 复制代码
flutter pub add sqflite path

并导入

dart 复制代码
import 'dart:async';

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

接下来我们就可以通过 SQL 语句建表了

dart 复制代码
await db.execute( 'CREATE TABLE Test (id INTEGER PRIMARY KEY, value TEXT)');

这行代码在SQLite数据库中创建了一个名为 Test 的表。该表有两列,id 和 value。 id 列是整数类型,被设定为主键,这意味着每一个 Test 表中的记录都应有一个唯一的 id。value 列是文本(字符串)类型,可以存储任意形式的文本信息。

然后,我们可以像这样进行写入操作:

csharp 复制代码
await db.transaction((txn) async {
  int id1 = await txn.rawInsert(
      'INSERT INTO Test(value) VALUES("flutter sqlite")');
});

我们首先开始一个数据库事务,然后在该事务中执行一个 rawInsert 操作。在这个操作中,我们向名为 Test 的表中插入一行数据,该行数据的 value 字段的值为 flutter sqlite。这个操作是异步的,所以我们用await关键字等待它完成。这个操作完成后,它会返回新插入行的id,我们将这个id保存在变量id1中。完成所有操作后,事务会自动提交。

这和前端的 IndexedDB 一样,都是一个事务型数据库系,如同SQL-based RDBMS。我们可以通过 window.indexedDB.open 打开一个数据库后进行正删改查操作

js 复制代码
var db;
var request = window.indexedDB.open("TestDB", 1);
request.onerror = function(event) {
  console.log("error: ");
};
request.onsuccess = function(event) {
  db = request.result;
  console.log("success: "+ db);
};

TestDB 如果不存在则会自动创建,后面那个 1 是版本号的意思。然后我们在CRUD 时也会看到 transaction 这个关键字

dart 复制代码
var request = db.transaction(["Test"], "readwrite") 
              .request.objectStore("Test") 
              .add({ id: "01", name: "John", age: 30, email: "john@example.com" });

这段代码是在IndexedDB中添加数据的例子。首先,通过db.transaction(["Test"], "readwrite")开启一个读写事务。参数"Test"表示要操作的对象存储空间名称,"readwrite"表示这是一个可以进行读写操作的事务。

然后,通过.request.objectStore("Test")获取名为"Test"的对象存储空间。

接着,调用.add({ id: "01", name: "John", age: 30, email: "john@example.com" })向对象存储空间中添加一个对象。这个对象的id为"01",name为"John",age为30,email为"john@example.com"。

如果这个操作成功,IndexedDB会存储这个对象。如果对象存储空间中已经存在一个id为"01"的对象,这个操作会失败,并触发错误事件。

文件存储

文件存储稍微复杂有一点点,不是因为 API 复杂,是因为稍微需要懂一点点原生开发的知识,首先我们要搞清楚文件存储是存到哪里?但其实我们只要用 path_provider 这个封装好的包帮我们处理跨平台的事情,我们不需要搞清楚 IOS 和 Android 存储系统的差异,我们直接找到 2个移动端开发常用的存储位置 应用目录 和 临时目录。

应用目录是用于存储应用产生的文件,这些文件仅对应用自身可见,且会随着应用的卸载而删除。下面是获取应用文档目录的代码示例:

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

void getApplicationDocumentsDirectoryPath() async {
  final directory = await getApplicationDocumentsDirectory();
  print('Application Documents Directory: ${directory.path}');
}

临时目录是用于存储临时文件的,这些文件可以随时被系统清理。下面是获取临时目录的代码示例:

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

void getTemporaryDirectoryPath() async {
  final directory = await getTemporaryDirectory();
  print('Temporary Directory: ${directory.path}');
}

获取到文件存储的路径后,我们可以使用Dart的 dart:io 库来进行文件读写。首先,我们需要创建一个File 对象,然后调用它的 writeAsString 方法来写入数据,或者调用 readAsString 方法来读取数据。下面是一个简单的示例:

dart 复制代码
import 'dart:io';

void writeFile(String path, String text) async {
  final file = File(path);
  await file.writeAsString(text);
}

void readFile(String path) async {
  final file = File(path);
  String text = await file.readAsString();
}
相关推荐
马可家的菠萝30 分钟前
自动保存已经有了,为什么笔记软件还需要“历史版本”?
前端·后端·架构
半个落月1 小时前
从 "use client" 到 Route Handler:用 Todos 理解 Next.js 水合与全栈请求
前端·react.js·next.js
qq_452396231 小时前
第七篇:《大型前端项目的模块化与目录结构设计》
前端
你脑门上的脚印1 小时前
Vue 项目从零实现语音转文字、文字转语音功能(完整可用 + 踩坑指南)
前端·vue.js
paopaokaka_luck1 小时前
基于springboot3+vue3的车间生产管理系统(Echarts图形化分析、BI报表)
java·前端·spring boot·学习·echarts
程序员鱼皮1 小时前
3 大 DeepSeek Harness 进阶玩法,招多个大肥鱼帮我干活!
前端·后端·ai编程
KoPa1 小时前
HeySmart:大模型开源网关基座-请求生命周期与钩子引擎
前端·后端
七牛开发者2 小时前
Coding Agent 如何跑稳长任务?从上下文管理到运行时状态
前端·javascript·后端
半个落月2 小时前
从 CSR 到 Server Component:吃透 Next.js 16 App Router 路由、布局与 SEO
前端·next.js
七牛开发者2 小时前
拆解 DeepSeek Harness:Profile 与 Bundle 如何装配运行时
前端·javascript·后端