W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
應(yīng)用程序中通常會包含一些貫穿 APP 生命周期的變量信息,這些信息在 APP 大多數(shù)地方可能都會被用到,比如當(dāng)前用戶信息、Local 信息等。在 Flutter 中我們把需要全局共享的信息分為兩類:全局變量和共享狀態(tài)。全局變量就是單純指會貫穿整個 APP 生命周期的變量,用于單純的保存一些信息,或者封裝一些全局工具和方法的對象。而共享狀態(tài)則是指哪些需要跨組件或跨路由共享的信息,這些信息通常也是全局變量,而共享狀態(tài)和全局變量的不同在于前者發(fā)生改變時需要通知所有使用該狀態(tài)的組件,而后者不需要。為此,我們將全局變量和共享狀態(tài)分開單獨管理。
我們在“l(fā)ib/common”目錄下創(chuàng)建一個Global
類,它主要管理 APP 的全局變量,定義如下:
// 提供五套可選主題色
const _themes = <MaterialColor>[
Colors.blue,
Colors.cyan,
Colors.teal,
Colors.green,
Colors.red,
];
class Global {
static SharedPreferences _prefs;
static Profile profile = Profile();
// 網(wǎng)絡(luò)緩存對象
static NetCache netCache = NetCache();
// 可選的主題列表
static List<MaterialColor> get themes => _themes;
// 是否為release版
static bool get isRelease => bool.fromEnvironment("dart.vm.product");
//初始化全局信息,會在APP啟動時執(zhí)行
static Future init() async {
_prefs = await SharedPreferences.getInstance();
var _profile = _prefs.getString("profile");
if (_profile != null) {
try {
profile = Profile.fromJson(jsonDecode(_profile));
} catch (e) {
print(e);
}
}
// 如果沒有緩存策略,設(shè)置默認緩存策略
profile.cache = profile.cache ?? CacheConfig()
..enable = true
..maxAge = 3600
..maxCount = 100;
//初始化網(wǎng)絡(luò)請求相關(guān)配置
Git.init();
}
// 持久化Profile信息
static saveProfile() =>
_prefs.setString("profile", jsonEncode(profile.toJson()));
}
Global 類的各個字段的意義都有注釋,在此不再贅述,需要注意的是init()
需要在 App 啟動時就要執(zhí)行,所以應(yīng)用的main
方法如下:
void main() => Global.init().then((e) => runApp(MyApp()));
在此,一定要確保Global.init()
方法不能拋出異常,否則 runApp(MyApp())
根本執(zhí)行不到。
有了全局變量,我們還需要考慮如何跨組件共享狀態(tài)。當(dāng)然,如果我們將要共享的狀態(tài)全部用全局變量替代也是可以的,但是這在 Flutter 開發(fā)中并不是一個好主意,因為組件的狀態(tài)是和 UI 相關(guān),而在狀態(tài)改變時我們會期望依賴該狀態(tài)的 UI 組件會自動更新,如果使用全局變量,那么我們必須得去手動處理狀態(tài)變動通知、接收機制以及變量和組件依賴關(guān)系。因此,本實例中,我們使用前面介紹過的 Provider 包來實現(xiàn)跨組件狀態(tài)共享,因此我們需要定義相關(guān)的 Provider。在本實例中,需要共享的狀態(tài)有登錄用戶信息、APP 主題信息、APP 語言信息。由于這些信息改變后都要立即通知其它依賴的該信息的 Widget 更新,所以我們應(yīng)該使用ChangeNotifierProvider
,另外,這些信息改變后都是需要更新 Profile 信息并進行持久化的。綜上所述,我們可以定義一個ProfileChangeNotifier
基類,然后讓需要共享的 Model 繼承自該類即可,ProfileChangeNotifier
定義如下:
class ProfileChangeNotifier extends ChangeNotifier {
Profile get _profile => Global.profile;
@override
void notifyListeners() {
Global.saveProfile(); //保存Profile變更
super.notifyListeners(); //通知依賴的Widget更新
}
}
用戶狀態(tài)在登錄狀態(tài)發(fā)生變化時更新、通知其依賴項,我們定義如下:
class UserModel extends ProfileChangeNotifier {
User get user => _profile.user;
// APP是否登錄(如果有用戶信息,則證明登錄過)
bool get isLogin => user != null;
//用戶信息發(fā)生變化,更新用戶信息并通知依賴它的子孫Widgets更新
set user(User user) {
if (user?.login != _profile.user?.login) {
_profile.lastLogin = _profile.user?.login;
_profile.user = user;
notifyListeners();
}
}
}
主題狀態(tài)在用戶更換 APP 主題時更新、通知其依賴項,定義如下:
class ThemeModel extends ProfileChangeNotifier {
// 獲取當(dāng)前主題,如果為設(shè)置主題,則默認使用藍色主題
ColorSwatch get theme => Global.themes
.firstWhere((e) => e.value == _profile.theme, orElse: () => Colors.blue);
// 主題改變后,通知其依賴項,新主題會立即生效
set theme(ColorSwatch color) {
if (color != theme) {
_profile.theme = color[500].value;
notifyListeners();
}
}
}
當(dāng) APP 語言選為跟隨系統(tǒng)(Auto)時,在系通語言改變時,APP 語言會更新;當(dāng)用戶在 APP 中選定了具體語言時(美國英語或中文簡體),則 APP 便會一直使用用戶選定的語言,不會再隨系統(tǒng)語言而變。語言狀態(tài)類定義如下:
class LocaleModel extends ProfileChangeNotifier {
// 獲取當(dāng)前用戶的APP語言配置Locale類,如果為null,則語言跟隨系統(tǒng)語言
Locale getLocale() {
if (_profile.locale == null) return null;
var t = _profile.locale.split("_");
return Locale(t[0], t[1]);
}
// 獲取當(dāng)前Locale的字符串表示
String get locale => _profile.locale;
// 用戶改變APP語言后,通知依賴項更新,新語言會立即生效
set locale(String locale) {
if (locale != _profile.locale) {
_profile.locale = locale;
notifyListeners();
}
}
}
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: