一、文件IO
PathProvider 插件提供了一种平台透明的方式来访问设备文件系统上的常用位置。该类当前支持访问两个文件系统位置:
- 临时目录: 系统可随时清除的临时目录(缓存)。在iOS上,这对应于NSTemporaryDirectory() 返回的值。在Android上,这是getCacheDir()返回的值。
- 文档目录: 应用程序的目录,用于存储只有自己可以访问的文件。只有当应用程序被卸载时,系统才会清除该目录。在iOS上,这对应于NSDocumentDirectory。在Android上,这是AppData目录。
1)在pubspec.yaml中添加path_provider库
dependencies:
path_provider: 0.4.1
2)在dart文件中实现文件读写方法
import 'dart:io';
import 'package:path_provider/path_provider.dart';
读文件:
Future<File> _getLocalFile() async {
// get the path to the document directory.
String dir = (await getApplicationDocumentsDirectory()).path;
return new File('$dir/counter.txt');
}
Future<int> _readCounter() async {
try {
File file = await _getLocalFile();
// read the variable as a string from the file.
String contents = await file.readAsString();
return int.parse(contents);
} on FileSystemException {
return 0;
}
}
getApplicationDocumentsDirectory这一行代码的路径对应到Android路径下是:
/data/data/com.example.flutterhello/app_flutter
写文件:
await (await _getLocalFile()).writeAsString('$_counter');
通过库中的接口可以直接实现从File读写string
二、Json操作
Flutter有一个内置dart:convert库,其中包含一个简单的JSON编码器和解码器。
{
"name": "John Smith",
"email": "john@example.com"
}
有了dart:convert,我们可以用两种方式来序列化这个JSON model。
1)内连序列化JSON
Map<String, dynamic> user = JSON.decode(json);
print('Howdy, ${user['name']}!');
print('We sent the verification link to ${user['email']}.');
JSON.decode()仅返回一个Map<String, dynamic>,这意味着我们直到运行时才知道值的类型,这样就失去了大部分静态类型语言特性:类型安全、自动补全和最重要的编译时异常。这样一来,代码可能会变得非常容易出错。
2)在模型类中序列化JSON
可以通过引入一个简单的模型类(model class)来解决前面提到的问题,称之为User。在User类内部,我们有:
一个User.fromJson 构造函数, 用于从一个map构造出一个 User实例 map structure
一个toJson 方法, 将 User 实例转化为一个map.
class User {
final String name;
final String email;
User(this.name, this.email);
User.fromJson(Map<String, dynamic> json)
: name = json['name'],
email = json['email'];
Map<String, dynamic> toJson() =>
{
'name': name,
'email': email,
};
}
现在,序列化逻辑移到了模型本身内部。采用这种新方法,可以非常容易地反序列化user。
Map userMap = JSON.decode(json);
var user = new User.fromJson(userMap);
print('Howdy, ${user.name}!');
print('We sent the verification link to ${user.email}.');
要序列化一个user,我们只是将该User对象传递给该JSON.encode方法。我们不需要手动调用toJson这个方法,因为JSON.encode已经为我们做了。
String json = JSON.encode(user);
3)使用代码生成库序列化JSON
这种json处理方式需要在项目中设置json_serializable,要包含json_serializable到我们的项目中,需要一个常规和两个开发依赖项。简而言之,开发依赖项是不包含在我们的应用程序源代码中的依赖项。
dependencies:
json_annotation: ^2.0.0
dev_dependencies:
build_runner: ^1.0.0
json_serializable: ^2.0.0
将我们的User类转换为一个json_serializable:
import 'package:json_annotation/json_annotation.dart';
// user.g.dart 将在我们运行生成命令后自动生成
part 'user.g.dart';
///这个标注是告诉生成器,这个类是需要生成Model类的
@JsonSerializable()
class User {
User(this.name, this.email);
String name;
String email;
//不同的类使用不同的mixin即可
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}
有了这个设置,源码生成器将生成用于序列化name和email字段的JSON代码。
有两种生成序列化的方式:
第一种,一次性生成
项目根目录下运行flutter packages pub run build_runner build,我们可以在需要时为我们的model生成json序列化代码。 这触发了一次性构建,它通过我们的源文件,挑选相关的并为它们生成必要的序列化代码。
可以看到在user.dart所在的目录下生成了user.g.dart文件,内容如下:
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'user.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
User _$UserFromJson(Map<String, dynamic> json) {
return User(json['name'] as String, json['email'] as String);
}
Map<String, dynamic> _$UserToJson(User instance) =>
<String, dynamic>{'name': instance.name, 'email': instance.email};
第二种,持续生成
使用_watcher_可以使源代码生成的过程更加方便。它会监视项目中文件的变化,并在需要时自动构建必要的文件。可以通过flutter packages pub run build_runner watch在项目根目录下运行来启动_watcher_。只需启动一次观察器,然后并让它在后台运行,这是安全的。
可以动态的在user.dart中添加变量id,可以自动更新对应目下的user.g.dart文件:
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'user.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
User _$UserFromJson(Map<String, dynamic> json) {
return User(
json['name'] as String, json['email'] as String, json['id'] as String);
}
Map<String, dynamic> _$UserToJson(User instance) => <String, dynamic>{
'name': instance.name,
'email': instance.email,
'id': instance.id
};
4)使用json_serializable模型
要通过json_serializable方式反序列化JSON字符串,不需要对先前的代码进行任何更改。
Map userMap = JSON.decode(json);
var user = new User.fromJson(userMap);
序列化也一样。调用API与之前相同。
String json = JSON.encode(user);
有了json_serializable,我们可以在User类上忘记任何手动的JSON序列化 。源代码生成器创建一个名为user.g.dart的文件,它具有所有必需的序列化逻辑。
三、shared_preferences
shared_preferences 包含了Android的SharedPreferences接口和iOS的NSUserDefaults接口。
1)在pubspec.yaml添加库支持
https://pub.dartlang.org/packages/shared_preferences
dependencies:
flutter:
sdk: flutter
shared_preferences: "0.4.3"
2)获取实例写数据
final prefs = await SharedPreferences.getInstance();
// Try reading data from the counter key. If it does not exist, return 0.
final counter = prefs.getInt('counter') ?? 0;
3)保存数据
// obtain shared preferences
final prefs = await SharedPreferences.getInstance();
// set value
prefs.setInt('counter', counter);
4)删除数据
final prefs = await SharedPreferences.getInstance();
prefs.remove('counter');
5)支持的数据类型
支持的数据类型是:int, double, bool, string and stringList
不支持写大量的数据。
另外需要注意的是,获取SharedPreferences是阻塞式的,因为get数据的时候如果mMap没有初始化就一直等着:
_loadCounter() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
_counter = (prefs.getInt('counter') ?? 0);
});
}