Flutter 資料儲存之SharedPreferences
我們在做APP開發時, 經常會涉及到使用者資料的儲存(比如儲存使用者登入token、使用者的某些偏好設定等). 開發過Android的朋友應該知道有 SharedPreferences. 在 Flutter 中, 同樣為我們提供了十分相似的(甚至名字都一樣)元件, 為我們提供資料儲存的能力.
本篇教程將用一個簡單的小Demo, 讓你完全掌握 資料儲存之SharedPreferences 的用法.
若圖片展示異常, 請訪問我的官方部落格
效果
有圖有真相, 我們先來看一下我們最終的效果:
倉庫地址
所有原始碼(含註釋)均已上傳至開源倉庫:
準備工作
開發環境
本部落格的環境一覽:
環境 | 版本號 |
---|---|
Flutter | 1.14.6 beta |
Dart | 2.8.0-dev.5.0 |
Android Studio | 3.5.2 |
注意您的環境和文中的差異, 避免出現不相容的情況哦!
需具備的條件
要順利閱讀本文, 假定您已經具備以下條件:
- 一臺電腦(能同時執行IDE、APP模擬器).
Android Studio
或VSCode
(或任何你喜歡的程式碼編輯器).Flutter
開發環境.- 您掌握了
Flutter
的開發基礎(至少了解目錄結構、Dart
語言基本知識).
實戰開始
建立Flutter專案
建立一個新的Flutter專案, 命名為my_shared_preferences_demo
(您可以隨意起名, 但是在下面也要替換名字為您自己的).
注意: Flutter專案名不要和引入的某個第三方庫重名, 否則會報:
A package may not list itself as a dependency
程式碼截圖:
清理程式碼
因為我們的專案過於簡單, 暫時不需要進行測試. 刪除./test目錄:
避免冗餘程式碼誤導我們, 替換./lib/main.dart
為:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'SharedPreferences Demo',
home: MyHomePage(title: 'SharedPreferences Demo Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[],
),
),
);
}
}
複製程式碼
匯入 SharedPreferences 第三方庫
進入./pubspec.yaml
, 新增依賴:
dependencies:
shared_preferences: ^0.5.6+3
複製程式碼
你也可以去官網檢視最新的shared_preferences
截圖:
更新包, 在終端中輸入(或者點選IDE的更新包的按鈕):
flutter packages get
複製程式碼
執行專案:
現在, 我們可以正式進行資料儲存的操作了!
建立資料讀寫工具類
實際專案中, 我們定會多次用到資料的讀寫, 所以封裝一個工具類是比較明智的選擇.
建立./lib/shared_preferences_util.dart
建立SharedPreferencesUtil
類
class SharedPreferencesUtil {
}
複製程式碼
因為後面要用到SharedPreferences, 所以匯入shared_preferences:
import 'package:shared_preferences/shared_preferences.dart';
複製程式碼
資料儲存函式 saveData()
新增函式saveData()
:
/// 儲存資料
static saveData<T>(String key, T value) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
switch (T) {
case String:
prefs.setString(key, value as String);
break;
case int:
prefs.setInt(key, value as int);
break;
case bool:
prefs.setBool(key, value as bool);
break;
case double:
prefs.setDouble(key, value as double);
break;
}
}
複製程式碼
在定義函式時, 名稱後面多了一個"
<T>
", 這運用了泛型. 若對此有疑問, 請自行搜尋"dart 泛型"的相關知識.
程式碼解析: 函式要求傳入兩個值, key以及value. key為我們要存的值的"名字". 這個名字是唯一的, 後續我們在讀取資料的時候也需要傳入與這個key. value就是它對應的值. 函式體內, 我們先在首行引入一個SharedPreferences的例項, 便於後續使用. 使用
switch
分支, 用來判斷傳入的泛型型別. 判斷完成後, 分別呼叫prefs.setXXX(key, value)
, 完成資料儲存.
程式碼截圖:
資料讀取函式 getData()
有資料儲存函式, 自然也應該有與之對應的資料讀取函式, 我們來寫:
新增函式getData()
:
/// 讀取資料
static Future<T> getData<T>(String key) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
T res;
switch (T) {
case String:
res = prefs.getString(key) as T;
break;
case int:
res = prefs.getInt(key) as T;
break;
case bool:
res = prefs.getBool(key) as T;
break;
case double:
res = prefs.getDouble(key) as T;
break;
}
return res;
}
複製程式碼
程式碼解析: 與上面的
saveData()
函式類似, 同樣運用了泛型以及switch
. 不同的是讀取資料時呼叫的是prefs.getXXX()
程式碼截圖:
到這裡, 我們幾乎已經完成了我們的教程. 反應快的同學應該已經可以直接使用了. 但是阿航的教程要保證其完整性, 讓大家都會用, 並且理解為什麼這麼用. 我們來繪製APP介面, 更直觀的測試!
繪製用於測試工具類的簡單介面
回到./lib/main.dart
, 我們來增加幾個按鈕和輸入框.
匯入SharedPreferencesUtil
先匯入SharedPreferencesUtil
方便後續使用:
import 'package:my_shared_preferences_demo/shared_preferences_util.dart';
複製程式碼
定義例項變數
在_MyHomePageState
定義例項變數_savedValue
和_currentInputValue
, 用於記錄儲存及當前輸入的值:
// 儲存的值
String _savedValue = "載入中..";
// 當前輸入的值
String _currentInputValue;
複製程式碼
初始化頁面時載入資料.
定義initState()
, 在初始化頁面時讀取已存的資料
@override
void initState() {
super.initState();
SharedPreferencesUtil.getData<String>("myData").then((value) {
setState(() {
_savedValue = value;
});
});
}
複製程式碼
程式碼解析: 可以看到
initState()
上有@override
, 因為initState()
為繼承過來的函式. 函式內部先呼叫super.initState()
. 接下來就是通過此前定義的SharedPreferencesUtil
獲取儲存的資料. 因為shared_preferences
提供的函式是async
(非同步)的, 所以需要通過.then()
來保證其獲取到資料後再進行後續操作. 獲取到value後, 存至_savedValue.
接下來就是繪製介面了, 在build
->Scaffold
->body:Center
->child: Column
->children
中新增以下程式碼塊:
// 用於顯示資料的Text
Text(
_savedValue == null ? "無資料" : _savedValue,
style: TextStyle(fontSize: 60, fontWeight: FontWeight.bold),
),
// 用於修改資料的輸入框
TextField(
onChanged: (value) {
_currentInputValue = value;
},
// 僅為美觀, 增加輸入框的邊框
decoration: InputDecoration(
contentPadding: EdgeInsets.all(10.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15.0),
)),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
// 用於觸發儲存資料的按鈕
RaisedButton(
child: Text("儲存"),
onPressed: () {
// 當點選按鈕時, 呼叫儲存資料的函式
SharedPreferencesUtil.saveData<String>(
"myData", _currentInputValue);
// 同時渲染當前顯示的儲存的值
setState(() {
_savedValue = _currentInputValue;
});
},
),
RaisedButton(
child: Text("清空資料"),
onPressed: () {
// 當點選按鈕時, 呼叫儲存資料的函式
SharedPreferencesUtil.saveData<String>("myData", null);
// 同時渲染當前顯示的儲存的值
setState(() {
_savedValue = "無資料";
});
},
)
],
),
複製程式碼
程式碼解析: 這裡雖然看起來程式碼多一點, 實質上只有1個輸入框和2個按鈕. 裡面沒有特別複雜的邏輯, 所有說明都在程式碼註釋中, 可自行檢視.
以上的程式碼截圖:
大功告成
若你的程式碼沒有問題, 執行專案, 效果應該是這樣的:
通過以上的一些步驟, 我們終於完成了 Flutter資料儲存之SharedPreference, 是不是很簡單?
倉庫地址
所有原始碼(含註釋)均已上傳至開源倉庫:
對文章若有任何問題、異議以及改進建議, 歡迎在下方進行評論. 作者將盡快回復! 若圖片展示異常, 歡迎閱讀官方部落格.
更多更好的教程/部落格/資訊, 歡迎訪問我的官網: 阿航的技術小站.