三种形式:文件 SharedPreferences 数据库
文件
文件是存储在某种介质(比如磁盘)上指定路径的、具有文件名的一组有序信息的集合。 定义文件的存储路径。
Flutter 提供了两种文件存储的目录,即临时(Temporary)目录与文档(Documents)目录、外部目录:
-
临时目录是操作系统可以随时清除的目录,通常被用来存放一些不重要的临时缓存数据。在 iOS 上对应着 NSTemporaryDirectory 返回的值,而在 Android 上则对应着 getCacheDir 返回的值。
-
文档目录则是只有在删除应用程序时才会被清除的目录,通常被用来存放应用产生的重要数据文件。在 iOS 上,对应着 NSDocumentDirectory,在 Android 上则对应着 AppData 目录。
-
外部存储目录:可以使用getExternalStorageDirectory()来获取外部存储目录,如SD卡;由于iOS不支持外部目录,所以在iOS下调用该方法会抛出UnsupportedError异常,而在Android下结果是android SDK中getExternalStorageDirectory的返回值。
在这里我们借助pathprovider插件来实现文件目录的创建读取写入。PathProvider 插件提供了一种平台透明的方式来访问设备文件系统上的常用位置。
1.引入PathProvider插件;在pubspec.yaml文件中添加如下声明:
path_provider: ^0.4.1
添加后,执行flutter packages get 获取一下, 版本号可能随着时间推移会发生变化,读者可以使用最新版。
2.代码实现
//创建文件目录
import 'dart:io';
import 'package:path_provider/path_provider.dart';
Future<File> get _localFile async {
// getTemporaryDirectory()//临时目录
// getApplicationDocumentsDirectory()//应用程序的文档目录
// getExternalStorageDirectory()外部储存目录
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
类似于Android的sp一样,适合少量的数据,且适合配置数据。需要借助插件shared_preferences。SharedPreferences 的使用方式非常简单方便。不过需要注意的是,以键值对的方式只能存储基本类型的数据,比如 int、double、bool 和 string。
1.添加插件,注意插件版本不要太新
shared_preferences: ^0.5.4
2.代码实现
//获取数据
Future<String> getSpContent() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String counter = (prefs.getString('content') ?? "");
return counter;
}
//设置数据
Future<void> setSPContent(String content) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString('content', content);
}
数据库 sqflite
flutter 也可以实现数据库的存储,数据库只适合大量数据的情况,少量数据使用文件或者sp就可以实现。这里我们使用的是sqflite插件来实现数据库的增删。如果我们需要持久化大量格式化后的数据,并且这些数据还会以较高的频率更新,为了考虑进一步的扩展性,我们通常会选用 sqlite 数据库来应对这样的场景。与文件和 SharedPreferences 相比,数据库在数据读写上可以提供更快、更灵活的解决方案。
sqflite: ^1.1.7+3
初始化数据库对象
抽象对象
abstract class DatabaseProvider {
Database _instance;
String get databaseName;// get方法
String get tableName;
Future<Database> get database async {
if (_instance == null) {
var path = await getDatabasesPath();
_instance = await openDatabase(
join(
path,
databaseName,
),
onCreate: createDatabase,
version: 1,
);
}
return _instance;
}
createDatabase(Database db, int version);
}
//子类继承父类,重写方法
class TestDatabaseProvider extends DatabaseProvider {
@override
String get databaseName => "test.db"; // 重写 get 方法
@override
String get tableName => "user";
/**
* 重写父类方法
*/
@override
createDatabase(Database db, int version) {
db.execute(
"""
CREATE TABLE user(
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT,
age TEXT
);
"""
);
}
}
调用
class _DbTestPageState extends State<DbTestPage> {
var insertResult;
static TestDatabaseProvider provider;
String queryResult = "--";
@override
void initState() {
// TODO: implement initState
super.initState();
// 初始化数据库对象
provider = TestDatabaseProvider();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("测试数据库的页面"),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: TextField(
onChanged: (value) => _saveInsert(value),
decoration: InputDecoration(
hintText: "请输入int-id,String-name,String-age",
prefixIcon: Icon(Icons.person)),
maxLines: 1,
textAlign: TextAlign.left,
obscureText: false,
// 隐藏正在编辑的内容
autofocus: true,
),
),
RaisedButton(
onPressed: () => _insertData(insertResult),
child: Text("插入"),
)
],
),
RaisedButton(
onPressed: _queryAll,
child: Text("查询所有"),
),
Text(queryResult,style: TextStyle(),) ,
],
),
);
}
_saveInsert(String value) => insertResult = value;
_insertData(var insertResult) async {
if (insertResult.isEmpty) {
return;
}
List list = insertResult.split(",");
UserEntity user = UserEntity();
user.id = int.parse(list[0]);
user.name = list[1];
user.age = list[2];
Database database = await provider.database;
await database
.insert(provider.tableName, user.toJson())
.then((value) => {print("_insertData--$value")});
}
void _queryAll() async {
queryResult="-----\n";
Database database = await provider.database;
Future<List<Map<Object, dynamic>>> future =
database.query(provider.tableName);
future.then((List<Map<Object, dynamic>> list) {
for (Map<Object, dynamic> map in list) {
for (var key in map.keys) {
print("key=${key}--value=${map[key]}");
setState(() {
queryResult = queryResult+"$key:${map[key]}\n" ;
});
}
}
});
}
}
效果图