前面的幾篇文章主要介紹了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
未完待續。。。