博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Flutter 构建完整应用手册-持久化
阅读量:6436 次
发布时间:2019-06-23

本文共 7541 字,大约阅读时间需要 25 分钟。

hot3.png

将键值数据存储在磁盘上

如果我们有一小部分我们想要保存的键值,我们可以使用插件。

通常我们不得不编写原生平台集成来存储这两个平台的数据。 幸运的是,插件可用于此目的。 共享偏好设置插件包装iOS上的NSUserDefaults和Android上的SharedPreferences,为简单数据提供持久存储。

建立

在我们开始之前,我们需要将插件添加到我们的pubspec.yaml文件中:

dependencies:  flutter:    sdk: flutter  shared_preferences: "
"

保存数据

要持久化键值数据,我们可以使用SharedPreferences类。 为了保存数据,我们调用set方法。 请注意,数据是异步持久的。 如果我们想要在保存数据时得到通知,请使用commit()函数。

// obtain shared preferences SharedPreferences prefs = await SharedPreferences.getInstance();// set new valueprefs.setInt('counter', counter);

读取数据

SharedPreferences prefs = await SharedPreferences.getInstance();int counter = (prefs.getInt('counter') ?? 0) + 1;

在上面的例子中,我们从counter键加载数据,如果它不存在,则返回0。

移除数据

SharedPreferences prefs = await SharedPreferences.getInstance();prefs.remove('counter');

Setter和getter方法适用于所有原始类。

支持的类型

虽然使用键值存储非常简单方便,但它有一些限制:

  • 只能使用原始类型:int, double, bool, string 和 string list
  • 它不是用来存储大量数据,因此不适合作为应用程序缓存。

有关Android上共享首选项的更多信息,请访问Android开发人员网站上的。

例子

import 'package:flutter/material.dart';import 'package:shared_preferences/shared_preferences.dart';void main() => runApp(new MyApp());class MyApp extends StatelessWidget {  // This widget is the root of our application.  @override  Widget build(BuildContext context) {    return new MaterialApp(      title: 'Shared preferences demo',      theme: new ThemeData(        primarySwatch: Colors.blue,      ),      home: new MyHomePage(title: 'Shared preferences demo'),    );  }}class MyHomePage extends StatefulWidget {  MyHomePage({Key key, this.title}) : super(key: key);  final String title;  @override  _MyHomePageState createState() => new _MyHomePageState();}class _MyHomePageState extends State
{ int _counter = 0; @override void initState() { super.initState(); _loadCounter(); } //Loading counter value on start _loadCounter() async { SharedPreferences prefs = await SharedPreferences.getInstance(); setState(() { _counter = (prefs.getInt('counter') ?? 0); }); } //Incrementing counter after click _incrementCounter() async { SharedPreferences prefs = await SharedPreferences.getInstance(); _counter = (prefs.getInt('counter') ?? 0) + 1; setState(() { _counter; }); prefs.setInt('counter', _counter); } @override Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar( title: new Text(widget.title), ), body: new Center( child: new Column( mainAxisAlignment: MainAxisAlignment.center, children:
[ new Text( 'You have pushed the button this many times:', ), new Text( '$_counter', style: Theme.of(context).textTheme.display1, ), ], ), ), floatingActionButton: new FloatingActionButton( onPressed: _incrementCounter, tooltip: 'Increment', child: new Icon(Icons.add), ), // This trailing comma makes auto-formatting nicer for build methods. ); }}

测试支持

通过运行以下代码,我们可以在我们的测试中使用初始值填充SharedPreferences:

const MethodChannel('plugins.flutter.io/shared_preferences')  .setMockMethodCallHandler((MethodCall methodCall) async {    if (methodCall.method == 'getAll') {      return 
{}; // set initial values here if desired } return null; });

上面的代码应放在测试文件夹下的测试文件中。

读写文件

在某些情况下,将文件读取和写入磁盘可能非常方便。 这可用于跨应用程序启动持续保存数据或从互联网上下载数据并保存以供以后脱机使用。

为了将文件保存到磁盘,我们需要将插件与库结合使用。

路线

  • 找到正确的本地路径
  • 创建对文件位置的引用
  • 将数据写入文件
  • 从文件中读取数据

1.找到正确的本地路径

在这个例子中,我们将显示一个计数器。 当计数器发生变化时,我们需要在磁盘上写入数据,以便在应用程序加载时再次读取它。 因此,我们需要问:我们应该在哪里存储这些数据?

插件提供了一种平台不可知的方式来访问设备文件系统上的常用位置。 该插件当前支持访问两个系统文件位置:

  • 临时目录: 一个临时目录(缓存),系统可以随时清除。 在iOS上,这对应于返回的值。 在Android上,这是返回的值。
  • 文档目录:应用程序的目录,用于存储只有它可以访问的文件。 只有当应用程序被删除时,系统才会清除目录。 在iOS上,这对应于NSDocumentDirectory。 在Android上,这是AppData目录。

在我们的例子中,我们希望将信息存储在文档目录中! 我们可以像这样找到文档目录的路径:

Future
get _localPath async { final directory = await getApplicationDocumentsDirectory(); return directory.path;}

2.创建对文件位置的引用

一旦我们知道在哪里存储文件,我们需要创建一个文件的完整位置的引用。 我们可以使用库中的类来实现此目的。

Future
get _localFile async { final path = await _localPath; return new File('$path/counter.txt');}

3.将数据写入文件

现在我们有一个File可以使用,我们可以使用它来读取和写入数据! 首先,我们将一些数据写入文件。 由于我们正在使用计数器,因此我们只会将整数存储为字符串。

Future
writeCounter(int counter) async { final file = await _localFile; // Write the file return file.writeAsString('$counter');}

4.从文件中读取数据

现在我们在磁盘上有一些数据,我们可以阅读它! 再次,我们将使用File类来完成此操作。

Future
readCounter() async { try { final file = await _localFile; // Read the file String contents = await file.readAsString(); return int.parse(contents); } catch (e) { // If we encounter an error, return 0 return 0; }}

测试

为了测试与文件交互的代码,我们需要模拟对MethodChannel的调用。 MethodChannel是Flutter用来与主机平台进行通信的类。

在我们的测试中,我们无法与设备上的文件系统进行交互。 我们需要与我们的测试环境的文件系统进行交互!

为了模拟方法调用,我们可以在我们的测试文件中提供一个setupAll函数。 该功能将在测试执行之前运行。

setUpAll(() async {  // Create a temporary directory to work with  final directory = await Directory.systemTemp.createTemp();    // Mock out the MethodChannel for the path_provider plugin  const MethodChannel('plugins.flutter.io/path_provider')      .setMockMethodCallHandler((MethodCall methodCall) async {    // If we're getting the apps documents directory, return the path to the    // temp directory on our test environment instead.    if (methodCall.method == 'getApplicationDocumentsDirectory') {      return directory.path;    }    return null;  });});

完整例子

import 'dart:async';import 'dart:io';import 'package:flutter/foundation.dart';import 'package:flutter/material.dart';import 'package:path_provider/path_provider.dart';void main() {  runApp(    new MaterialApp(      title: 'Reading and Writing Files',      home: new FlutterDemo(storage: new CounterStorage()),    ),  );}class CounterStorage {  Future
get _localPath async { final directory = await getApplicationDocumentsDirectory(); return directory.path; } Future
get _localFile async { final path = await _localPath; return new File('$path/counter.txt'); } Future
readCounter() async { try { final file = await _localFile; // Read the file String contents = await file.readAsString(); return int.parse(contents); } catch (e) { // If we encounter an error, return 0 return 0; } } Future
writeCounter(int counter) async { final file = await _localFile; // Write the file return file.writeAsString('$counter'); }}class FlutterDemo extends StatefulWidget { final CounterStorage storage; FlutterDemo({Key key, @required this.storage}) : super(key: key); @override _FlutterDemoState createState() => new _FlutterDemoState();}class _FlutterDemoState extends State
{ int _counter; @override void initState() { super.initState(); widget.storage.readCounter().then((int value) { setState(() { _counter = value; }); }); } Future
_incrementCounter() async { setState(() { _counter++; }); // write the variable as a string to the file return widget.storage.writeCounter(_counter); } @override Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar(title: new Text('Reading and Writing Files')), body: new Center( child: new Text( 'Button tapped $_counter time${_counter == 1 ? '' : 's'}.', ), ), floatingActionButton: new FloatingActionButton( onPressed: _incrementCounter, tooltip: 'Increment', child: new Icon(Icons.add), ), ); }}

 

转载于:https://my.oschina.net/u/3647851/blog/1791974

你可能感兴趣的文章
Mysql学习总结(5)——MySql常用函数大全讲解
查看>>
Exchange Server 2007迁移Exchange Server 2010 (16)--- OWA重定向
查看>>
Effective C++:unio
查看>>
Shell中的一些小技巧
查看>>
iptables tcp wrappers
查看>>
俩虚拟机间通过ssh互相登陆
查看>>
第一天作业笔记
查看>>
Linux 内核链表剖析(二十)
查看>>
MySQL授权用户及密码恢复设置
查看>>
基础交换
查看>>
web开发的跨域问题详解
查看>>
13.1-13.3 设置更改root密码,连接MySQL,MySQL常用命令
查看>>
【VMware vSAN 6.6】5.8.自动化:vSAN硬件服务器解决方案
查看>>
spring boot 配置文件
查看>>
小牛带你nginx反向代理中神奇的斜线
查看>>
Android Studio 2.1.2 升级到 2.2之后,gradle 编译版本更新为2.2.0,databinding报错
查看>>
今天来谈谈Python中的各种排序总结,含实现代码
查看>>
怎样将WPS转换word格式?如何进行操作
查看>>
针对不同创业阶段的创业者适合参加哪些创业赛事活动呢?创业是一场异常艰辛的马拉松,坚持是唯一的捷径,借...
查看>>
Linux中bash文档翻译
查看>>