Flutter入門進(jìn)階之旅(十二)Flutter 數(shù)據(jù)存儲(chǔ)

前言

之前的章節(jié)我們基本上把Flutter中基礎(chǔ)部分的東西都做了簡(jiǎn)單的講解,通過(guò)前面章節(jié)的循序?qū)W習(xí)讀者也基本能完成一些簡(jiǎn)單的UI繪制并能利用Flutter處理一些簡(jiǎn)單的用戶交互,讀者可能也留意到埃篓,我們之前的章節(jié)中所學(xué)習(xí)到的內(nèi)容并沒有涉及到數(shù)據(jù)存儲(chǔ)方面的操作,或者說(shuō)贩毕,我們到現(xiàn)在為止并不知道在Flutter中數(shù)據(jù)應(yīng)該怎么存些己,存在哪。本篇博文中筆者將會(huì)為大家解決這一疑惑潜必。

關(guān)于Flutter中的數(shù)據(jù)存儲(chǔ)

相信做過(guò)原生Android開發(fā)的讀者對(duì)數(shù)據(jù)存儲(chǔ)并不陌生,在原生Android中我們會(huì)把一些輕量級(jí)的數(shù)據(jù)(如用戶信息沃但、APP配置信息等)寫入SharedPreferences做存儲(chǔ)磁滚,把需要長(zhǎng)期存儲(chǔ)的數(shù)據(jù)寫入本地文件或者Sqlite3,當(dāng)然Flutter中也同樣用一套完整的本地?cái)?shù)據(jù)存儲(chǔ)體系宵晚,下面我們就一直來(lái)了解下上述提到的這3中本地存儲(chǔ)方式在Flutter中使用垂攘。

1.SharedPreferences

在Flutter中本身并沒有內(nèi)置SharedPreferences存儲(chǔ),但是官方給我們提供了第三方的組件來(lái)實(shí)現(xiàn)這一存儲(chǔ)方式淤刃。我們可以通過(guò)pubspec.yaml文件引入晒他,關(guān)于pubspec.yaml的使用我們?cè)?a href="http://www.reibang.com/p/f20877589072" target="_blank">Flutter入門進(jìn)階之旅(五)Image Widget,這一章節(jié)提到過(guò),只不過(guò)在Image使用中我們引入的是assets文件依賴逸贾。

如下我們?cè)赿ependencies節(jié)點(diǎn)下引入SharedPreferences的依賴陨仅,讀者在pubspec.yaml引入依賴時(shí)一定要注意代碼縮進(jìn)格式,否則在在執(zhí)行flutter packages get時(shí)很可能會(huì)報(bào)錯(cuò)铝侵。


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

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

然后命令行執(zhí)行flutter packages get把遠(yuǎn)程依賴同步到本地灼伤,在此筆者寫文章的時(shí)候sharedPreference的最新版本是0.5.0,讀者可自行去https://pub.dartlang.org/flutter上獲取最新版本咪鲜,同時(shí)也可以在上面找到其他需要引入的資源依賴包狐赡。

筆者的話

啰里啰嗦的準(zhǔn)備工作總算是講完了,主要是今天的課程涉及到了包依賴管理疟丙,可能對(duì)于有些初學(xué)者有點(diǎn)懵颖侄,所以我就借助sharedPreference把依賴引入廢話扯了一大通鸟雏,如果讀者已經(jīng)掌握了上述操作,可跳過(guò)準(zhǔn)備工作直接到下面的部分览祖。

繼續(xù)上面的內(nèi)容崔慧,我們先來(lái)體驗(yàn)一下sharedPreference,貼個(gè)圖大家放松一下穴墅。


sharedPreference

從上圖中我們看到我們使用sharedPreference做了簡(jiǎn)單存儲(chǔ)跟獲取的操作惶室,其實(shí)sharedPreference好像也就這么點(diǎn)左右,不是存就是取玄货。讀者在自行操作時(shí)一定不要忘記導(dǎo)入sharedPreference的包

import 'package:shared_preferences/shared_preferences.dart';

存數(shù)據(jù)

跟原生Android一樣皇钞,F(xiàn)lutter中操作sp也是通過(guò)key-value的方式存取數(shù)據(jù)

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

SharedPreferences中為我們提供了String、bool松捉、Double夹界、Int、StringList數(shù)據(jù)類型的存取隘世。

SharedPreferences

取數(shù)據(jù)

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

上述操作邏輯中我們通過(guò)_textFieldController獲取在TextField中的值可柿,在按下存儲(chǔ)按鈕的同時(shí)我們把數(shù)據(jù)寫入sp中,當(dāng)按下獲取值的時(shí)候我們通過(guò)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存儲(chǔ)數(shù)據(jù)
   */
  Future saveString() async {
    SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
    sharedPreferences.setString(
        STORAGE_KEY, _textFieldController.value.text.toString());
  }

  /**
   * 獲取存在SharedPreferences中的數(shù)據(jù)
   */
  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('數(shù)據(jù)存儲(chǔ)'),
      ),
      body: new Column(
        children: <Widget>[
          Text("shared_preferences存儲(chǔ)", textAlign: TextAlign.center),
          TextField(
            controller: _textFieldController,
          ),
          MaterialButton(
            onPressed: saveString,
            child: new Text("存儲(chǔ)"),
            color: Colors.pink,
          ),
          MaterialButton(
            onPressed: getString,
            child: new Text("獲取"),
            color: Colors.lightGreen,
          ),
          Text('shared_preferences存儲(chǔ)的值為  $_storageString'),


        ],
      ),
    );
  }
}

2.文件存儲(chǔ)

雖然我們今天內(nèi)容是Flutter的數(shù)據(jù)存儲(chǔ)复斥,尷尬的是Flutter本身都沒有內(nèi)置提到的這三種存儲(chǔ)方式,不過(guò)好在官方給我們提供了三方的支持庫(kù)械媒,不知道后續(xù)的Flutter版本中會(huì)不會(huì)對(duì)此做改進(jìn)目锭。操作文件同樣我們也需要像SharedPreferences一樣,需要在pubspec.yaml引入纷捞。在 Flutter 里實(shí)現(xiàn)文件讀寫痢虹,需要使用 path_provider 和 dart 的 io 模塊。path_provider 負(fù)責(zé)查找 iOS/Android 的目錄文件主儡,IO 模塊負(fù)責(zé)對(duì)文件進(jìn)行讀寫

  # 添加文件依賴
  path_provider: ^0.5.0

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

由于整個(gè)操作演示邏輯跟SharedPreferences一樣糜值,我就不詳細(xì)講解文件存儲(chǔ)中關(guān)于存取數(shù)據(jù)的具體操作了丰捷,稍微我貼上源代碼,讀者自行查閱代碼對(duì)比即可臀玄,關(guān)于文件存儲(chǔ)的三個(gè)獲取文件路徑的方法我這里說(shuō)明一下瓢阴,做過(guò)原生Android開發(fā)的讀者可能對(duì)此不陌生畅蹂,但是ios或者初學(xué)者可能并不了解這個(gè)概念健无,所以我想提出來(lái)說(shuō)明一下。

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

  • getTemporaryDirectory()//獲取應(yīng)用緩存目錄液斜,等同IOS的NSTemporaryDirectory()和Android的getCacheDir() 方法
  • getApplicationDocumentsDirectory()獲取應(yīng)用文件目錄類似于Ios的NSDocumentDirectory和Android上的 AppData目錄
  • getExternalStorageDirectory()//這個(gè)是存儲(chǔ)卡累贤,僅僅在Android平臺(tái)可以使用

來(lái)看下操作文件的效果圖

文件存儲(chǔ)

借用了SharedPreferences存儲(chǔ)的邏輯叠穆,只是把存儲(chǔ)的代碼放在了file.text中,代碼里有詳盡的注釋臼膏,我就不多做解釋說(shuō)明了硼被,讀者可自行嘗試對(duì)比跟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 = '';

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

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

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

    //獲取存儲(chǔ)路徑
    final filePath = fileDirectory.path;

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

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

3.Sqflite

在Flutter中的數(shù)據(jù)庫(kù)叫Sqflite跟原生安卓的Sqlite叫法不一樣。我們來(lái)看下Sqflite官方對(duì)它的解釋說(shuō)明:

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

通過(guò)上面的描述渗磅,我們了解到Sqflite是一個(gè)同時(shí)支持Android跟Ios平臺(tái)的數(shù)據(jù)庫(kù)嚷硫,并且支持標(biāo)準(zhǔn)的CURD操作,下面我們還是用上面操作文件跟sp的代碼邏輯是一塊體驗(yàn)一下Sqflite始鱼。

同樣需要引入依賴:

  #添加Sqflite依賴
  sqflite: ^1.0.0

模擬場(chǎng)景:

利用Sqflite創(chuàng)建一張user表仔掸,其中user表中id設(shè)置為主鍵id,且為自增長(zhǎng)医清,name字段為text類型起暮,用戶按下存儲(chǔ)按鈕后,把TextFile輸入框里的內(nèi)容插入到user表中会烙,當(dāng)按下獲取按鈕時(shí)负懦,取出數(shù)據(jù)庫(kù)中最后一條數(shù)據(jù)顯示在下方Text上,并且顯示出當(dāng)前數(shù)據(jù)庫(kù)中一共有多少條數(shù)據(jù)柏腻,以及數(shù)據(jù)庫(kù)的存儲(chǔ)路徑纸厉。

效果圖

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數(shù)據(jù)庫(kù)存儲(chǔ)數(shù)據(jù)
   */
  saveString() async {
    final db = await getDataBase('my_db.db');
    //寫入字符串
    db.transaction((trx) {
      trx.rawInsert(
          'INSERT INTO user(name) VALUES("${_textFieldController.value.text.toString()}")');
    });
  }

  /**
   * 獲取存在Sqflite數(shù)據(jù)庫(kù)中的數(shù)據(jù)
   */
  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;
        //獲取數(shù)據(jù)庫(kù)中的最后一條數(shù)據(jù)
        _storageString = lists[listSize - 1]['name'] +
            "\n現(xiàn)在數(shù)據(jù)庫(kù)中一共有${listSize}條數(shù)據(jù)" +
            "\n數(shù)據(jù)庫(kù)的存儲(chǔ)路徑為${dbPath}";
      });
    });
  }

  /**
   * 初始化數(shù)據(jù)庫(kù)存儲(chǔ)路徑
   */
  Future<Database> getDataBase(String dbName) async {
    //獲取應(yīng)用文件目錄類似于Ios的NSDocumentDirectory和Android上的 AppData目錄
    final fileDirectory = await getApplicationDocumentsDirectory();

    //獲取存儲(chǔ)路徑
    final dbPath = fileDirectory.path;

    //構(gòu)建數(shù)據(jù)庫(kù)對(duì)象
    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('數(shù)據(jù)存儲(chǔ)'),
      ),
      body: new Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Text("Sqflite數(shù)據(jù)庫(kù)存儲(chǔ)", textAlign: TextAlign.center),
          TextField(
            controller: _textFieldController,
          ),
          MaterialButton(
            onPressed: saveString,
            child: new Text("存儲(chǔ)"),
            color: Colors.cyan,
          ),
          MaterialButton(
            onPressed: getString,
            child: new Text("獲取"),
            color: Colors.deepOrange,
          ),
          Text('從Sqflite數(shù)據(jù)庫(kù)中獲取的值為  $_storageString'),
        ],
      ),
    );
  }
}

至此,關(guān)于Flutter的本地存儲(chǔ)相關(guān)的內(nèi)容就全部講解完了五嫂,在本文章中残腌,我為了清晰代碼結(jié)構(gòu)跟業(yè)務(wù)邏輯,復(fù)用的都是同一個(gè)存儲(chǔ)業(yè)務(wù)邏輯跟UI便于大家結(jié)合代碼做對(duì)比贫导,讀者可結(jié)合代碼自行對(duì)比三種存儲(chǔ)方式的細(xì)節(jié)差別抛猫。

下一篇:Flutter入門進(jìn)階之旅(十三)Flutter 路由

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市孩灯,隨后出現(xiàn)的幾起案子闺金,更是在濱河造成了極大的恐慌,老刑警劉巖峰档,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件败匹,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡讥巡,警方通過(guò)查閱死者的電腦和手機(jī)掀亩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)欢顷,“玉大人槽棍,你說(shuō)我怎么就攤上這事。” “怎么了炼七?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵缆巧,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我豌拙,道長(zhǎng)陕悬,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任按傅,我火速辦了婚禮捉超,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘唯绍。我一直安慰自己狂秦,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布推捐。 她就那樣靜靜地躺著裂问,像睡著了一般。 火紅的嫁衣襯著肌膚如雪牛柒。 梳的紋絲不亂的頭發(fā)上堪簿,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音皮壁,去河邊找鬼椭更。 笑死,一個(gè)胖子當(dāng)著我的面吹牛蛾魄,可吹牛的內(nèi)容都是我干的虑瀑。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼滴须,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼舌狗!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起扔水,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤痛侍,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后魔市,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體主届,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年待德,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了君丁。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡将宪,死狀恐怖绘闷,靈堂內(nèi)的尸體忽然破棺而出橡庞,到底是詐尸還是另有隱情,我是刑警寧澤簸喂,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布毙死,位于F島的核電站燎潮,受9級(jí)特大地震影響喻鳄,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜确封,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一除呵、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧爪喘,春花似錦颜曾、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至侦鹏,卻和暖如春诡曙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背略水。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工价卤, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人渊涝。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓慎璧,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親跨释。 傳聞我的和親對(duì)象是個(gè)殘疾皇子胸私,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容