在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_mode
和 volume
都是键,random
和 0.7
分别是要存储的值,表示播放模式和音量大小。当你需要获取这个值时,可以使用 getString
和 getFloat
方法,如下所示:
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();
}