赞
踩
Flutter
提供了三种数据持久化方法,即文件、SharedPreferences 与数据库
。
Flutter
提供了两种文件存储的目录,即临时(Temporary
)目录与文档(Documents
)目录:
临时目录是操作系统可以随时清除的目录,通常被用来存放一些不重要的临时缓存数据。这个目录在 iOS
上对应着 NSTemporaryDirectory
返回的值(网上搜集的信息,对 iOS 不熟悉故不确定对错)
,而在 Android
上则对应着 getCacheDir
返回的值。
文档目录则是只有在删除应用程序时才会被清除的目录,通常被用来存放应用产生的重要数据文件。在 iOS
上,这个目录对应着 NSDocumentDirectory (网上搜集的信息,对iOS不熟悉故不确定对错)
,而在 Android
上则对应着 AppData
目录。
如何在Flutter
中获取上述两个目录地址呢?这里使用到的是 path_provider库
先在pubspec.yaml
中添加依赖,然后点击AndroidStudio
右上角的 packages get
dependencies:
path_provider: ^1.6.5
接下来就可以获取到以上两个目录路径了:
// 获取临时目录
Directory tempDir = await getTemporaryDirectory();
String tempPath = tempDir.path;
// 获取文档目录
Directory appDocDir = await getApplicationDocumentsDirectory();
String appDocPath = appDocDir.path;
接下来我们通过示例来看一下效果。
创建文件并写入数据,随后将数据读取出来。由于文件读写一般比较耗时且容易出错,为了保证程序的健壮性,需要异步
Futures
以及try catch
使用。
首先在文档目录创建文件:
Future<File> get _localFile async {
// 存在文档目录
final directory = await getApplicationDocumentsDirectory();
final path = directory.path;
// 使用绝对路径
return File('$path/content.txt');
}
接着在文件中写入数据:
Future<File> writeContent(String content) async {
// 获取到文件
final file = await _localFile;
// 执行写入
return file.writeAsString(content);
}
最后将上一步写入的数据读取出来:
Future<String> readContent() async {
try {
// 获取到文件
final file = await _localFile;
// 执行读取
String contents = await file.readAsString();
return contents;
} catch (e) {
return "";
}
}
效果图:
文件比较适合大量的、有序的数据持久化,如果我们只是需要缓存少量的键值对信息(比如记录用户是否阅读了公告,或是简单的计数),则可以使用 SharedPreferences。
接下来我们通过示例来看一下效果。
首先引入库:shared_preferences
dependencies:
shared_preferences: ^0.5.6+3
然后往 SP 中写入数据:
// 获得实例
Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
// 写入数据
_prefs.then((sp) => {
sp.setString('hello', '你好 SharedPreferences')
});
最后将之前写入的数据读取出来:
// 获得实例
Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
// 取出数据
_prefs.then((sp) {
setState(() {
mContent = sp.getString('hello');// 通过可 key 取出 value
});
});
封装之后使用,源码地址:shared_preferences.dart
先看示例效果:
跳转网页那块有点慢,录制 gif 的时候直接跳过了,所以在详情页面会短暂显示空白
使用流程:
SharedPrefernces
对象,item
然后将数据存入到 SharedPrefernces
中,SharedPrefernces
中的数据。具体使用可查看 Flutter-WanAndroid 项目
SharedPrefernces
的使用固然方便,但这种方式只适用于持久化少量数据的场景,我们并不能用它来存储大量数据。原因是在Android
中使用SharedPrefernces
存储的文件过大会导致读取速度变慢还可能出现内存抖动问题,iOS
不熟悉这块也没法描述。为了解决以上问题,通常会选用 sqlite 数据库来本地化存储稍大量的数据。
往数据库中添加三个学生的数据,然后读取出学生的姓名。
1. 首先引入库:sqflite
dependencies:
...
sqflite: ^1.3.0
2. 创建数据库,并调用初始化方法,我这里是在initState()
调用:
join
方法可能会爆红,在顶部引入path
库即可
import 'package:path/path.dart';
Future<void> initDataBase() async { dataBase = await openDatabase( join(await getDatabasesPath(), 'students_database.db'), onCreate: (db, version) => db.execute( "CREATE TABLE students(id TEXT PRIMARY KEY, name TEXT, score INTEGER)"), onUpgrade: (db, oldVersion, newVersion) { //dosth for migration print("old:$oldVersion,new:$newVersion"); }, version: 1, ); print("database:$dataBase"); } // 调用初始化 @override void initState() { initDataBase(); super.initState(); }
3. 存入数据:
// 创建 Student 对象 class Student { String id; String name; int score; Student({ this.id, this.name, this.score, }); factory Student.fromJson(Map<String, dynamic> parsedJson) { return Student( id: parsedJson['id'], name: parsedJson['name'], score: parsedJson['score'], ); } Map<String, dynamic> toJson() { return { 'id': id, 'name': name, 'score': score, }; } } // 插入数据库 中的 students 表 Future<void> insertStudent(Student std) async { await dataBase.insert( 'students', std.toJson(), conflictAlgorithm: ConflictAlgorithm.replace, ); } // 调用插入数据方法 insertData() async { var student1 = Student(id: '0', name: '张三', score: 90); var student2 = Student(id: '1', name: '李四', score: 80); var student3 = Student(id: '2', name: '王五', score: 85); // Insert a dog into the database. await insertStudent(student1); await insertStudent(student2); await insertStudent(student3); }
4. 取出数据:
// 查询 students 表的数据
Future<List<Student>> students() async {
final List<Map<String, dynamic>> maps = await dataBase.query('students');
return List.generate(maps.length, (i) => Student.fromJson(maps[i]));
}
// 转为 string 输出
getStudents() async {
await students()
.then((list) => list.forEach((s) => sb.writeln(s.toJson().toString())));
setState(() {
mContext = sb.toString();
});
}
5. 关闭数据库:
@override
void dispose() {
dataBase.close();
super.dispose();
}
以上就是数据库的基本使用,使用步骤略有繁琐,我们可以封装了之后再使用。
参考 flutter-go
封装之后使用,源码地址:
先看示例效果:
本地收藏数据库实现。跳转网页那块有点慢,录制 gif 的时候直接跳过了,所以在详情页面会短暂显示空白。
以下文件请在 Flutter-WanAndroid 项目中查找
使用流程:
main.dart
文件中初始化。具体的初始化逻辑在utils/provider.dart
文件中 // 数据库初始化
await provider.init(true);
utils/sql.dart
文件中,便于操作数据库。model/collect.dart
文件中,先创建到 Collection
对象和在数据库中创建表格,并在里面实现model
的数据库逻辑操作。 // 例如:插入新收藏
Future insert(Collection collection) {
var result =
sql.insert({'id': collection.id, 'title': collection.title, 'link':collection.link});
return result;
}
详情页面
用户点击收藏图标时调用model/collect.dart 中的 insert
方法插入数据库。// 插入操作 _collectionControl .insert(Collection( id: widget.id.toString(), title: widget.title, link: widget.link)) .then((result) { if (this.mounted) { setState(() { _hasCollected = true; }); print("收藏成功"); // 发送事件给 收藏页面,显示数据 if (ApplicationEvent.event != null) { ApplicationEvent.event .fire(CollectionEvent(widget.title, _link, false)); } } });
views/collection_page.dart
页面展示收藏的数据。 void _getList() {
_collectionList.clear();
_collectionControl.getAllCollection().then((resultList) {
resultList.forEach((item) {
_collectionList.add(item);
});
if (this.mounted) {
setState(() {
_collectionList = _collectionList;
});
}
});
}
具体使用可查看 Flutter-WanAndroid 项目。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。