Flutter 數據持久化

前面的幾篇文章主要介紹了flutter裏面基本控件的使用(其實我也沒細說到底咋用,就是堆出來的一個個小控件分享給大家-。-),本文主要介紹一下flutter中數據持久化的使用,作者也是邊學習邊碼文,和大家共同學習。

首先說學習過程中遇到的第一個場景,就是在做登錄頁面的時候,會聯想到我們實際應用中會需要存儲用戶輸入的用戶名和密碼,再或者登錄成功之後接口返回的一些其他用戶信息。在做iOS開發的時候,我們經常把這些輕量級的數據存在NSUserDefault中,其實在flutter中也有對應的SharedPreferences做輕量級的數據存儲,下面一起來學習一下。

1.SharedPreferences

shared_preferences是Flutter社區開發的一個本地數據存取插件。我們可以通過pubspec.yaml文件引入

dependencies:
  flutter:
    sdk: flutter

  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^0.1.2
  shared_preferences: ^0.5.3+2

然後執行flutter packages get

在使用的文件中引入

import 'package:shared_preferences/shared_preferences.dart';

這裏注意第一次run的時候會報錯要去iOS文件目錄中pod install 一下

常用的“增,刪,改,查”都可以在源碼API中找到,下面以登錄頁面爲例,應用一下:

可以看到支持bool,double,int,string,stringList幾種數據類型。

首次登錄是存儲用戶名(手機號)和 密碼:

 _login() async {
    print('login action');
    SharedPreferences prefs = await SharedPreferences.getInstance();

    await prefs.setString('name', _nameController.text);
    await prefs.setString('pwd', _passwordController.text);
    _getLoginInfor();
  }

再次登錄的時候獲取存在SharedPreferences中的數據:

_getLoginInfor() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    setState(() {
      _nameController.text = prefs.getString('name');
    }); 
  
  }

當然也有刪除的api:

/// Removes an entry from persistent storage.
  Future<bool> remove(String key) => _setValue(null, key, null);

我們看到支持存儲的幾種數據格式裏並沒有var,是不支持自定義類型的,比如我們的userInfoModel,所以這裏我們可以把登錄成功之後接口返回的json數據以字符串的形式存儲,在存儲前先不進行model轉換。(這裏測試用了本地json數據)

_getLoginInforJSON() async {
    String jsonStr = await DefaultAssetBundle.of(context).loadString("assets/json/login_info.json");
    Map<String, dynamic> jsonMap = json.decode(jsonStr);
    UserinfoModel model = UserinfoModel.fromJson(jsonMap);
    SharedPreferences prefs = await SharedPreferences.getInstance();

    await prefs.setString('loginInfo', jsonStr);
  }

還有些我們可能會用到的API

/// Returns true if persistent storage the contains the given [key].
  bool containsKey(String key) => _preferenceCache.containsKey(key);

/// Completes with true once the user preferences for the app has been cleared.
  Future<bool> clear() async {
    _preferenceCache.clear();
    return await _kChannel.invokeMethod<bool>('clear');
  }

2.文件存儲

在使用的文件裏添加引用

import 'dart:io';

直接看使用吧,和上面SharedPreferences的使用做同樣的功能

_save() async {
    File file = await _getFile('login.text');
    file.writeAsString(_nameController.text);
  }

  _getString() async {
    File file = await _getFile('login.text');
    setState(() {
      file.readAsString().then((String value) {
        _nameController.text = value;
      });
    });
  }

這裏主要關注一下文件路徑的獲取

_getFile(String fileName) async {
    Directory fileDirectory = await getApplicationDocumentsDirectory();
    String filePath = fileDirectory.path;
    return new File(filePath + "/" + fileName);
  }

就是getApplicationDocumentsDirectory();需要導入第三方的插件path_provider,path_provider是基於Directory的一個封裝

dependencies:
  flutter:
    sdk: flutter

  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^0.1.2
  
  shared_preferences: ^0.5.3+2
  # 添加文件依賴
  path_provider: ^1.1.2

裏面只有三個獲取路徑的API

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

根據打印的存儲路徑可以找到我們剛纔創建的文件,並查看是否存儲成功

創建文件成功

寫用戶名(手機號)成功

這裏補充一下關於目錄(Directory)的操作

  • 創建指定目錄
  • 重命名目錄
  • 刪除目錄
  • 創建臨時文件夾
  • 獲取父目錄
  • 列出目錄的內容
handleDir() async {
    Directory fileDirectory = await getApplicationDocumentsDirectory();
    String filePath = fileDirectory.path;
    //可以用Platform.pathSeparator代替路徑中的分隔符"/"
    //效果和"dir/subdir"一樣
    //如果有子文件夾,需要設置recursive: true
    var directory = await new Directory(filePath + "${Platform.pathSeparator}" + 'myfile')
        .create(recursive: true);

    assert(await directory.exists() == true);
    //輸出絕對路徑
    print("Path: ${directory.absolute.path}");

    //重命名文件夾
    directory = await directory.rename(filePath + "${Platform.pathSeparator}" + 'myfileRename');
    print("Path: ${directory.absolute.path}\n");

    //創建臨時文件夾
    //參數是文件夾的前綴,後面會自動添加隨機字符串
    //參數可以是空參數
    var tempDir = await Directory.systemTemp.createTemp('temp_dir');
    assert(await tempDir.exists() == true);
    print("Temp Path: ${tempDir.path}");

    //返回上一級文件夾
    var parentDir = tempDir.parent;
    print("Parent Path: ${parentDir.path}");

    //列出所有文件,不包括鏈接和子文件夾
    Stream<FileSystemEntity> entityList =
        parentDir.list(recursive: false, followLinks: false);
    await for (FileSystemEntity entity in entityList) {
      //文件、目錄和鏈接都繼承自FileSystemEntity
      //FileSystemEntity.type靜態函數返回值爲FileSystemEntityType
      //FileSystemEntityType有三個常量:
      //Directory、FILE、LINK、NOT_FOUND
      //FileSystemEntity.isFile .isLink .isDerectory可用於判斷類型
      print(entity.path);
    }

    //刪除目錄
    await tempDir.delete();
    assert(await tempDir.exists() == false);
  }

這裏需要注意的是,目錄操作也是要基於getApplicationDocumentsDirectory()獲取到Documents的路徑,或者創建臨時文件夾。

除了上述常用的API之外,file.dart中還提供了很多其他的API感興趣的小夥伴可以點進去查看,下面是一些其他常用方法的示例:

_saveWithInk() async {
    File file = await _getFile('loginInk.text');
    var sink = file.openWrite();
    sink.write(_nameController.text.toString());

    // Close the IOSink to free system resources.
    sink.close();
  }

  _delete() async {
    File file = await _getFile('loginInk.text');
    file.delete();
  }

_getFile(String fileName) async {
    Directory fileDirectory = await getApplicationDocumentsDirectory();
    String filePath = fileDirectory.path;
    print('filepath is $filePath');
    var file = File(filePath + "/" + fileName);
    try {
      bool exists = await file.exists();
      if (!exists) {
        return await file.create();
      } else {
        return file;
      }
    } catch (e) {
      print(e);
    }
  }

_save() async {
    File file = await _getFile('login.text');
    file.writeAsString(_nameController.text.toString()).then((File file) {
      // Do something with the file.
    });
    file.length().then((len) {
      print(len);
    });
  }

3.Sqflite
未完待續。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章