Flutter入門進階之旅(十二)Flutter 數據存儲

前言

以前的章節咱們基本上把Flutter中基礎部分的東西都作了簡單的講解,經過前面章節的循序學習讀者也基本能完成一些簡單的UI繪製並能利用Flutter處理一些簡單的用戶交互,讀者可能也留意到,咱們以前的章節中所學習到的內容並無涉及到數據存儲方面的操做,或者說,咱們到如今爲止並不知道在Flutter中數據應該怎麼存,存在哪。本篇博文中筆者將會爲你們解決這一疑惑。java

關於Flutter中的數據存儲

相信作過原生Android開發的讀者對數據存儲並不陌生,在原生Android中咱們會把一些輕量級的數據(如用戶信息、APP配置信息等)寫入SharedPreferences作存儲,把須要長期存儲的數據寫入本地文件或者Sqlite3,固然Flutter中也一樣用一套完整的本地數據存儲體系,下面咱們就一直來了解下上述提到的這3中本地存儲方式在Flutter中使用。ios

1.SharedPreferences

在Flutter中自己並無內置SharedPreferences存儲,可是官方給咱們提供了第三方的組件來實現這一存儲方式。咱們能夠經過pubspec.yaml文件引入,關於pubspec.yaml的使用咱們在Flutter入門進階之旅(五)Image Widget,這一章節提到過,只不過在Image使用中咱們引入的是assets文件依賴。數據庫

以下咱們在dependencies節點下引入SharedPreferences的依賴,讀者在pubspec.yaml引入依賴時必定要注意代碼縮進格式,不然在在執行flutter packages get時極可能會報錯緩存

dependencies:
  flutter:
    sdk: flutter
    
  # 添加sharedPreference依賴
  shared_preferences: ^0.5.0

dev_dependencies:
  flutter_test:
    sdk: flutter
    
  # 引入本地資源圖片
  assets:
     - images/a.png
     - images/aaa.png
複製代碼

而後命令行執行flutter packages get把遠程依賴同步到本地,在此筆者寫文章的時候sharedPreference的最新版本是0.5.0,讀者可自行去pub.dartlang.org/flutter上獲取最新版本,同時也能夠在上面找到其餘須要引入的資源依賴包。app

筆者的話async

囉裏囉嗦的準備工做總算是講完了,主要是今天的課程涉及到了包依賴管理,可能對於有些初學者有點懵,因此我就藉助sharedPreference把依賴引入廢話扯了一大通,若是讀者已經掌握了上述操做,可跳過準備工做直接到下面的部分。ide

繼續上面的內容,咱們先來體驗一下sharedPreference,貼個圖你們放鬆一下。 學習

sharedPreference

從上圖中咱們看到咱們使用sharedPreference作了簡單存儲跟獲取的操做,其實sharedPreference好像也就這麼點左右,不是存就是取。讀者在自行操做時必定不要忘記導入sharedPreference的包ui

import 'package:shared_preferences/shared_preferences.dart';
複製代碼

存數據

跟原生Android同樣,Flutter中操做sp也是經過key-value的方式存取數據spa

/** * 利用SharedPreferences存儲數據 */
  Future saveString() async {
    SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
    sharedPreferences.setString(
        STORAGE_KEY, _textFieldController.value.text.toString());
  }
複製代碼

SharedPreferences中爲咱們提供了String、bool、Double、Int、StringList數據類型的存取。

SharedPreferences

取數據

/** * 獲取存在SharedPreferences中的數據 */
  Future getString() async {
    SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
    setState(() {
      _storageString = sharedPreferences.get(STORAGE_KEY);
    });
  }
複製代碼

上述操做邏輯中咱們經過_textFieldController獲取在TextField中的值,在按下存儲按鈕的同時咱們把數據寫入sp中,當按下獲取值的時候咱們經過setState把從sp中獲取的值同步更新到下面的Text上顯示。

完整代碼:

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

class StoragePage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => StorageState();
}

class StorageState extends State {
  var _textFieldController = new TextEditingController();
  var _storageString = '';
  final STORAGE_KEY = 'storage_key';

  /** * 利用SharedPreferences存儲數據 */
  Future saveString() async {
    SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
    sharedPreferences.setString(
        STORAGE_KEY, _textFieldController.value.text.toString());
  }

  /** * 獲取存在SharedPreferences中的數據 */
  Future getString() async {
    SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
    setState(() {
      _storageString = sharedPreferences.get(STORAGE_KEY);
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('數據存儲'),
      ),
      body: new Column(
        children: <Widget>[
          Text("shared_preferences存儲", textAlign: TextAlign.center),
          TextField(
            controller: _textFieldController,
          ),
          MaterialButton(
            onPressed: saveString,
            child: new Text("存儲"),
            color: Colors.pink,
          ),
          MaterialButton(
            onPressed: getString,
            child: new Text("獲取"),
            color: Colors.lightGreen,
          ),
          Text('shared_preferences存儲的值爲 $_storageString'),


        ],
      ),
    );
  }
}
複製代碼

2.文件存儲

雖然咱們今天內容是Flutter的數據存儲,尷尬的是Flutter自己都沒有內置提到的這三種存儲方式,不過好在官方給咱們提供了三方的支持庫,不知道後續的Flutter版本中會不會對此作改進。操做文件一樣咱們也須要像SharedPreferences同樣,須要在pubspec.yaml引入。在 Flutter 裏實現文件讀寫,須要使用 path_provider 和 dart 的 io 模塊。path_provider 負責查找 iOS/Android 的目錄文件,IO 模塊負責對文件進行讀寫

# 添加文件依賴
  path_provider: ^0.5.0
複製代碼

筆者在此引入的最新版本是0.5.0,讀者可自行去pub.dartlang.org/flutter上獲取最新版本。

因爲整個操做演示邏輯跟SharedPreferences同樣,我就不詳細講解文件存儲中關於存取數據的具體操做了,稍微我貼上源代碼,讀者自行查閱代碼對比便可,關於文件存儲的三個獲取文件路徑的方法我這裏說明一下,作過原生Android開發的讀者可能對此不陌生,可是ios或者初學者可能並不瞭解這個概念,因此我想提出來講明一下。

在path_provider中有三個獲取文件路徑的方法:

  • getTemporaryDirectory()//獲取應用緩存目錄,等同IOS的NSTemporaryDirectory()和Android的getCacheDir() 方法
  • getApplicationDocumentsDirectory()獲取應用文件目錄相似於Ios的NSDocumentDirectory和Android上的 AppData目錄
  • getExternalStorageDirectory()//這個是存儲卡,僅僅在Android平臺可使用

來看下操做文件的效果圖

文件存儲

借用了SharedPreferences存儲的邏輯,只是把存儲的代碼放在了file.text中,代碼裏有詳盡的註釋,我就很少作解釋說明了,讀者可自行嘗試對比跟SharedPreferences的差異

樣例代碼

import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:io';

class StoragePage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => StorageState();
}

class StorageState extends State {
  var _textFieldController = new TextEditingController();
  var _storageString = '';

  /** * 利用文件存儲數據 */
  saveString() async {
    final file = await getFile('file.text');
    //寫入字符串
    file.writeAsString(_textFieldController.value.text.toString());
  }

  /** * 獲取存在文件中的數據 */
  Future getString() async {
    final file = await getFile('file.text');
    var filePath  = file.path;
    setState(() {
      file.readAsString().then((String value) {
        _storageString = value +'\n文件存儲路徑:'+filePath;
      });
    });
  }

  /** * 初始化文件路徑 */
  Future<File> getFile(String fileName) async {
    //獲取應用文件目錄相似於Ios的NSDocumentDirectory和Android上的 AppData目錄
    final fileDirectory = await getApplicationDocumentsDirectory();

    //獲取存儲路徑
    final filePath = fileDirectory.path;

    //或者file對象(操做文件記得導入import 'dart:io')
    return new File(filePath + "/"+fileName);
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('數據存儲'),
      ),
      body: new Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Text("文件存儲", textAlign: TextAlign.center),
          TextField(
            controller: _textFieldController,
          ),
          MaterialButton(
            onPressed: saveString,
            child: new Text("存儲"),
            color: Colors.cyan,
          ),
          MaterialButton(
            onPressed: getString,
            child: new Text("獲取"),
            color: Colors.deepOrange,
          ),
          Text('從文件存儲中獲取的值爲 $_storageString'),
        ],
      ),
    );
  }
}
複製代碼

3.Sqflite

在Flutter中的數據庫叫Sqflite跟原生安卓的Sqlite叫法不同。咱們來看下Sqflite官方對它的解釋說明:

SQLite plugin for Flutter. Supports both iOS and Android.

 Support transactions and batches
 Automatic version managment during open
 Helpers for insert/query/update/delete queries
 DB operation executed in a background thread on iOS and Android
複製代碼

經過上面的描述,咱們瞭解到Sqflite是一個同時支持Android跟Ios平臺的數據庫,而且支持標準的CURD操做,下面咱們仍是用上面操做文件跟sp的代碼邏輯是一塊體驗一下Sqflite

一樣須要引入依賴:

#添加Sqflite依賴
  sqflite: ^1.0.0
複製代碼

模擬場景:

利用Sqflite建立一張user表,其中user表中id設置爲主鍵id,且爲自增加,name字段爲text類型,用戶按下存儲按鈕後,把TextFile輸入框裏的內容插入到user表中,當按下獲取按鈕時,取出數據庫中最後一條數據顯示在下方Text上,而且顯示出當前數據庫中一共有多少條數據,以及數據庫的存儲路徑。

效果圖

Sqflite
上述描述樣式代碼

import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:io';
import 'package:sqflite/sqflite.dart';

class StoragePage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => StorageState();
}

class StorageState extends State {
  var _textFieldController = new TextEditingController();
  var _storageString = '';

  /** * 利用Sqflite數據庫存儲數據 */
  saveString() async {
    final db = await getDataBase('my_db.db');
    //寫入字符串
    db.transaction((trx) {
      trx.rawInsert(
          'INSERT INTO user(name) VALUES("${_textFieldController.value.text.toString()}")');
    });
  }

  /** * 獲取存在Sqflite數據庫中的數據 */
  Future getString() async {
    final db = await getDataBase('my_db.db');
    var dbPath = db.path;
    setState(() {
      db.rawQuery('SELECT * FROM user').then((List<Map> lists) {
        print('----------------$lists');
        var listSize = lists.length;
        //獲取數據庫中的最後一條數據
        _storageString = lists[listSize - 1]['name'] +
            "\n如今數據庫中一共有${listSize}條數據" +
            "\n數據庫的存儲路徑爲${dbPath}";
      });
    });
  }

  /** * 初始化數據庫存儲路徑 */
  Future<Database> getDataBase(String dbName) async {
    //獲取應用文件目錄相似於Ios的NSDocumentDirectory和Android上的 AppData目錄
    final fileDirectory = await getApplicationDocumentsDirectory();

    //獲取存儲路徑
    final dbPath = fileDirectory.path;

    //構建數據庫對象
    Database database = await openDatabase(dbPath + "/" + dbName, version: 1, onCreate: (Database db, int version) async {
      await db.execute("CREATE TABLE user (id INTEGER PRIMARY KEY, name TEXT)");
    });

    return database;
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('數據存儲'),
      ),
      body: new Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Text("Sqflite數據庫存儲", textAlign: TextAlign.center),
          TextField(
            controller: _textFieldController,
          ),
          MaterialButton(
            onPressed: saveString,
            child: new Text("存儲"),
            color: Colors.cyan,
          ),
          MaterialButton(
            onPressed: getString,
            child: new Text("獲取"),
            color: Colors.deepOrange,
          ),
          Text('從Sqflite數據庫中獲取的值爲 $_storageString'),
        ],
      ),
    );
  }
}

複製代碼

至此,關於Flutter的本地存儲相關的內容就所有講解完了,在本文章中,我爲了清晰代碼結構跟業務邏輯,複用的都是同一個存儲業務邏輯跟UI便於你們結合代碼作對比,讀者可結合代碼自行對比三種存儲方式的細節差異。

相關文章
相關標籤/搜索