文章将会被同步至微信公众号:Android部落格
文章参考:https://flutterchina.club/json/
更多信息可以参考flutter官方教程:https://flutter.dev/docs/cookbook
一、文件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 {String dir &#61; (await getApplicationDocumentsDirectory()).path;return new File(&#39;$dir/counter.txt&#39;);
}Future<int> _readCounter() async {try {File file &#61; await _getLocalFile();String contents &#61; await file.readAsString();return int.parse(contents);} on FileSystemException {return 0;}
}
getApplicationDocumentsDirectory这一行代码的路径对应到Android路径下是&#xff1a;
/data/data/com.example.flutterhello/app_flutter
写文件&#xff1a;
await (await _getLocalFile()).writeAsString(&#39;$_counter&#39;);
通过库中的接口可以直接实现从File读写string
二、Json操作
Flutter有一个内置dart:convert库&#xff0c;其中包含一个简单的JSON编码器和解码器。
{"name": "John Smith","email": "john&#64;example.com"
}
有了dart:convert&#xff0c;我们可以用两种方式来序列化这个JSON model。
1&#xff09;内连序列化JSON
Map<String, dynamic> user &#61; JSON.decode(json);
print(&#39;Howdy, ${user[&#39;name&#39;]}!&#39;);
print(&#39;We sent the verification link to ${user[&#39;email&#39;]}.&#39;);
JSON.decode()仅返回一个Map&#xff0c;这意味着我们直到运行时才知道值的类型&#xff0c;这样就失去了大部分静态类型语言特性&#xff1a;类型安全、自动补全和最重要的编译时异常。这样一来&#xff0c;代码可能会变得非常容易出错。
2&#xff09;在模型类中序列化JSON
可以通过引入一个简单的模型类(model class)来解决前面提到的问题&#xff0c;称之为User。在User类内部&#xff0c;我们有&#xff1a;
一个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 &#61; json[&#39;name&#39;],email &#61; json[&#39;email&#39;];Map<String, dynamic> toJson() &#61;>{&#39;name&#39;: name,&#39;email&#39;: email,};
}
现在&#xff0c;序列化逻辑移到了模型本身内部。采用这种新方法&#xff0c;可以非常容易地反序列化user。
Map userMap &#61; JSON.decode(json);
var user &#61; new User.fromJson(userMap);
print(&#39;Howdy, ${user.name}!&#39;);
print(&#39;We sent the verification link to ${user.email}.&#39;);
要序列化一个user&#xff0c;我们只是将该User对象传递给该JSON.encode方法。我们不需要手动调用toJson这个方法&#xff0c;因为JSON.encode已经为我们做了。
String json &#61; JSON.encode(user);
3&#xff09;使用代码生成库序列化JSON
这种json处理方式需要在项目中设置json_serializable&#xff0c;要包含json_serializable到我们的项目中&#xff0c;需要一个常规和两个开发依赖项。简而言之&#xff0c;开发依赖项是不包含在我们的应用程序源代码中的依赖项。
dependencies:json_annotation: ^2.0.0
dev_dependencies:build_runner: ^1.0.0json_serializable: ^2.0.0
将我们的User类转换为一个json_serializable&#xff1a;
import &#39;package:json_annotation/json_annotation.dart&#39;;
// user.g.dart 将在我们运行生成命令后自动生成
part &#39;user.g.dart&#39;;
///这个标注是告诉生成器&#xff0c;这个类是需要生成Model类的
&#64;JsonSerializable()
class User {User(this.name, this.email);String name;String email;factory User.fromJson(Map<String, dynamic> json) &#61;> _$UserFromJson(json);Map<String, dynamic> toJson() &#61;> _$UserToJson(this);
}
有了这个设置&#xff0c;源码生成器将生成用于序列化name和email字段的JSON代码。
有两种生成序列化的方式&#xff1a;
第一种&#xff0c;一次性生成
项目根目录下运行flutter packages pub run build_runner build&#xff0c;我们可以在需要时为我们的model生成json序列化代码。 这触发了一次性构建&#xff0c;它通过我们的源文件&#xff0c;挑选相关的并为它们生成必要的序列化代码。
可以看到在user.dart所在的目录下生成了user.g.dart文件&#xff0c;内容如下&#xff1a;
part of &#39;user.dart&#39;;
User _$UserFromJson(Map<String, dynamic> json) {return User(json[&#39;name&#39;] as String, json[&#39;email&#39;] as String);
}Map<String, dynamic> _$UserToJson(User instance) &#61;><String, dynamic>{&#39;name&#39;: instance.name, &#39;email&#39;: instance.email};
第二种&#xff0c;持续生成
使用_watcher_可以使源代码生成的过程更加方便。它会监视项目中文件的变化&#xff0c;并在需要时自动构建必要的文件。可以通过flutter packages pub run build_runner watch在项目根目录下运行来启动_watcher_。只需启动一次观察器&#xff0c;然后并让它在后台运行&#xff0c;这是安全的。
可以动态的在user.dart中添加变量id&#xff0c;可以自动更新对应目下的user.g.dart文件&#xff1a;
part of &#39;user.dart&#39;;
User _$UserFromJson(Map<String, dynamic> json) {return User(json[&#39;name&#39;] as String, json[&#39;email&#39;] as String, json[&#39;id&#39;] as String);
}Map<String, dynamic> _$UserToJson(User instance) &#61;> <String, dynamic>{&#39;name&#39;: instance.name,&#39;email&#39;: instance.email,&#39;id&#39;: instance.id};
4&#xff09;使用json_serializable模型
要通过json_serializable方式反序列化JSON字符串&#xff0c;不需要对先前的代码进行任何更改。
Map userMap &#61; JSON.decode(json);
var user &#61; new User.fromJson(userMap);
序列化也一样。调用API与之前相同。
String json &#61; JSON.encode(user);
有了json_serializable&#xff0c;我们可以在User类上忘记任何手动的JSON序列化 。源代码生成器创建一个名为user.g.dart的文件&#xff0c;它具有所有必需的序列化逻辑。
三、shared_preferences
shared_preferences 包含了Android的SharedPreferences接口和iOS的NSUserDefaults接口。
1&#xff09;在pubspec.yaml添加库支持
https://pub.dartlang.org/packages/shared_preferences
dependencies:flutter:sdk: fluttershared_preferences: "0.4.3"
2&#xff09;获取实例写数据
final prefs &#61; await SharedPreferences.getInstance();
final counter &#61; prefs.getInt(&#39;counter&#39;) ?? 0;
3&#xff09;保存数据
final prefs &#61; await SharedPreferences.getInstance();
prefs.setInt(&#39;counter&#39;, counter);
4&#xff09;删除数据
final prefs &#61; await SharedPreferences.getInstance();prefs.remove(&#39;counter&#39;);
5&#xff09;支持的数据类型
支持的数据类型是&#xff1a;int, double, bool, string and stringList
不支持写大量的数据。
另外需要注意的是&#xff0c;获取SharedPreferences是阻塞式的&#xff0c;因为get数据的时候如果mMap没有初始化就一直等着&#xff1a;
_loadCounter() async {SharedPreferences prefs &#61; await SharedPreferences.getInstance();setState(() {_counter &#61; (prefs.getInt(&#39;counter&#39;) ?? 0);});}
详细分析见文章&#xff1a;Android SharedPreferences
微信公众号二维码&#xff1a;