需求:在登陆完成后需要缓存登录返回的信息 例如 字典对象,这些信息在我的页面有进行使用例如展示用户的名字等
技术要点:Provider Store ChangeNotifier 等
实现方式:
001 新建一个登陆页面的Provider
import 'package:flutter/foundation.dart';
import 'package:qianduoduo/models/login_model.dart';
import 'package:shared_preferences/shared_preferences.dart';
class LoginPageProvider with ChangeNotifier {
bool _isLogin = false;
get isLogin => _isLogin;
String _verifyStr = '获取验证码';
get verifyStr => _verifyStr;
/// 是否可以获取验证码,默认为`false`。
bool _available = true;
get available => _available;
changeLoginState(bool login) {
_isLogin = login;
notifyListeners();
}
changeVerifyStr(String verifyStr, bool available) {
_available = available;
_verifyStr = verifyStr;
notifyListeners();
}
LoginModel _getSMS;
get getSMS => _getSMS;
LoginModel _loginModel;
get loginModel => _loginModel;
changeLoginData(data) {
_loginModel = LoginModel.fromJson(data);
notifyListeners();
}
String _phone;
get phone => _phone;
savePhone(phone) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
if (phone == null) {
phone = prefs.getString('phone');
}
_phone = phone;
prefs.setString('phone', phone);
notifyListeners();
}
@override
void dispose() {
super.dispose();
}
}
002 将登陆返回的信息缓存起来
LoginPageProvider loginPageProvider =
Store.value<LoginPageProvider>(context);
loginPageProvider.changeLoginData(resultModel.data);
Store.value<OrderProvider>(context)
.takeOrderSuccess(
false, cardDataDetail.data.orderNo);
003 在我的页面拿到这个信息,如果有改变就立即通知其他页面。类似于IOS 通知机制
//显示正常
return Store.connect<LoginPageProvider>(
builder: (context, LoginPageProvider provider, child) {
LoginModel loginModel = provider.loginModel;
return Container()})
@override
Widget build(BuildContext context) {
return Container(
child: Store.connect<OrderProvider>(
builder: (context, orderProvider, child) {
print('选择了$context');
//监听订单抢单成功通知 跳转到第二个Tab页面
if (orderProvider.orderNo != null && orderProvider.orderNo.length > 0) {
currentIndex = 1;
//清空orderNo 恢复正常currentIndex
Store.value<OrderProvider>(context).takeOrderSuccess(false, '');
}
return Scaffold();
}),
);
005 Store管理类
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:qianduoduo/provider/login_page_provider.dart';
class Store {
static BuildContext context;
static BuildContext widgetCtx;
// 我们将会在main.dart中runAPP实例化init
static init({context, child}) {
return MultiProvider(
providers: [
ChangeNotifierProvider(builder: (_) => LoginPageProvider()),
],
child: child,
);
}
// 通过Provider.value<T>(context)获取状态数据
static T value<T>(context) {
return Provider.of(context, listen: false);
}
// 通过Consumer获取状态数据
static Consumer connect<T>({builder, child}) {
return Consumer<T>(builder: builder, child: child);
}
}
004 ChangeNotifier官方文档说明
A class that can be extended or mixed in that provides a change notification API using VoidCallback for notifications.
It is O(1) for adding listeners and O(N) for removing listeners and dispatching notifications (where N is the number of listeners).
一个可以被拓展或者多继承的类,提供一个改变的通知,使用无符号回调通知。添加监听是O(1)时间复杂度,移除或者执行通知是O(N)的时间复杂度
005 ChangeNotifier 源码解析
ChangeNotifier继承Listenable
class ChangeNotifier implements Listenable {
LinkedList<_ListenerEntry>? _listeners = LinkedList<_ListenerEntry>();
有个链表类型的属性istener。
几个关键的方法
001 添加监听
@override
void addListener(VoidCallback listener) {
assert(_debugAssertNotDisposed());
_listeners!.add(_ListenerEntry(listener));
}
002 移除监听
@override
void removeListener(VoidCallback listener) {
assert(_debugAssertNotDisposed());
for (final _ListenerEntry entry in _listeners!) {
if (entry.listener == listener) {
entry.unlink();
return;
}
}
}
003 释放监听
@mustCallSuper
void dispose() {
assert(_debugAssertNotDisposed());
_listeners = null;
}
查看LinkedList源码
/// Adds [entry] to the beginning of the linked list.
void addFirst(E entry) {
_insertBefore(_first, entry, updateFirst: true);
_first = entry;
}
/// Adds [entry] to the end of the linked list.
void add(E entry) {
_insertBefore(_first, entry, updateFirst: false);
}
/// Add [entries] to the end of the linked list.
void addAll(Iterable<E> entries) {
entries.forEach(add);
}
/// Removes [entry] from the linked list.
///
/// Returns false and does nothing if [entry] is not in this linked list.
///
/// This is equivalent to calling `entry.unlink()` if the entry is in this
/// list.
bool remove(E entry) {
if (entry._list != this) return false;
_unlink(entry); // Unlink will decrement length.
return true;
}
006 参考文献: