前言
Flutter女装商城项目中使用的为Provide 1.x (估计停止维护了) ,但是于项目结尾更改为Provider版本为3.x,现最新版本为 4.0.5 [2020年4月13日],所以我尝试将版本升级到最新版本,但是出现了或多或少的问题,通过查阅资料最终解决,现将解决方案记录如下。
Provider简介
Provider为开发者提供了状态管理的方案,可以通过Provider实现状态的统一管理。
个人理解:一个全局的状态存储变量,然后当这个变量改变时,其他使用该状态的进行全局页面的动态改变,有一种牵一发而动全身的感觉。
使用方法
- 添加provider依赖
dependencies:
...
# 状态管理
provider: ^4.0.5
...
- 新建Provider(以切换页面为例)
import 'package:flutter/material.dart';
// 切换底部导航栏
// 需要 混入[mixins] ChangeNotifier
class CurrentIndexProvider with ChangeNotifier {
int currentIndex = 0;
changeIndex(int newIndex) {
currentIndex = newIndex;
notifyListeners();
}
}
mixins 也是Dart实现多继承的一种方式,除此之外还有 继承[extends] 、 实现[implements], 且以上三种方式可以同时存在,但顺序要求extends -> mixins -> implements
- 引入provider
import 'package:provider/provider.dart';
- 创建顶层共享状态数据
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 需要用 MultiProvider 包裹
return MultiProvider(
providers:
// 添加页面的状态(其他Provider也是加在此位置)
ChangeNotifierProvider(create: (_) => CurrentIndexProvider()),
],
child: Container(
child: MaterialApp(
title: KString.mainTitle,
// Flutter女装商城
debugShowCheckedModeBanner: False,
// 路由
onGenerateRoute: Application.router.generator,
// 定制主题
theme: ThemeData(
primaryColor: KColor.primaryColor,
),
home: IndexPage(),
),
),
);
}
}
- 获取或修改当前状态【重点⭐️】
// 取到当前索引状态值
int currentIndex = Provider.of<CurrentIndexProvider>(context).currentIndex;
// 页面跳转
Provider.of<CurrentIndexProvider>(context, listen: False).changeIndex(index);
注意 ⭐️:在 Provider.of(context) 中有一个 bool 类型的 listen 参数,它代表了是否监听数据变化,默认为 true。
如果只是简单的获取值,获取状态,必须加入listen: False,否则会报:
Tried to listen to a value exposed with provider, from outside of the widget tree.
This is likely caused by an event handler (like a button's onPressed) that called
Provider.of without passing `listen: False`.
To fix, write:
Provider.of<$T>(context, listen: False);
It is unsupported because may pointlessly rebuild the widget associated to the
event handler, when the widget tree doesn't care about the value.
如果需要对当前页面或者当前Widget直接刷新,不能加listen: False,否则不会对当前页面进行实时的刷新。
- Consumer组件更新
@override
Widget build(BuildContext context) {
return Container(
// 宽度
width: ScreenUtil().setWidth(750),
// 颜色
color: Colors.white,
// 用 Consumer 包裹
child: Consumer<CartProvider>(
builder:
(BuildContext context, CartProvider cartProvide, Widget child) {
return Container(
...
);
},
),
);
}
如果需要对其复杂页面组件进行动态的修改,可以将其包裹在 Consumer 中,该组件可以限制控件刷新范围,导致调用的 context 页面范围刷新。
其中builder 可以简写为 builder: (context, cartProvide, _){…}