把Provider的测试过程记录一下
1. 创建一个flutter 工程,然后创建一个模型:CMyModel
class CMyModel extends ChangeNotifier{
late int val;
CMyModel(this.val){
debugPrint('CMyModel:inited');
}
void inc(){
val++;
debugPrint('CMyModel:inc invoked');
notifyListeners();
}
@override
void dispose(){
super.dispose();
debugPrint('CMyModel:disposed');
}
}
2. 把主类改写成如下:
1. 增加了最上层的 MultiProvider,里面包含了 ChangeNotifierProvider,它暴露了上面写的类 CMyModel
2. 增加了 getTitle() ,显示 CMyModel 中的值
class _MyHomePageState extends State {
@override
Widget build(BuildContext context) {
debugPrint('home build');
return MultiProvider(providers: [
ChangeNotifierProvider( create: (BuildContext context) => CMyModel(0))
],
builder: (context,child){
debugPrint('provider build');
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('You have pushed the button this many times:'),
getTitle(context),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: ()=>Provider.of(context,listen: false).inc(),
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
);
}
Widget getTitle(BuildContext context){
debugPrint('get title build');
return Text(
'${Provider.of(context,listen: false)?.val}',
);
}
}
启动并点击按钮打印如下:
flutter: home build
flutter: provider build
flutter: get title build
flutter: CMyModel:inited
flutter: CMyModel:inc invoked
没有刷新事件出现: 只是放在Provider中,并不会更新UI
我们可以用 Consumer 来让它刷新,具体不述。 我们换个方式 watch 来处理
3. 把 getTitle 改成如下:
Widget getTitle(BuildContext context){
debugPrint('get title build');
return Text(
'${context.watch().val}',
);
}
启动并点击按钮打印如下:
flutter: home build
flutter: provider build
flutter: get title build
flutter: CMyModel:inited
flutter: CMyModel:inc invoked
flutter: provider build
flutter: get title build
刷新事件出现了!需要显式的指明监控哪个对象
4. 添加一个新的类 CMyTitleWidget
class CMyTitleWidget extends StatefulWidget{
const CMyTitleWidget({super.key});
@override
State createState()=>_CMyTitleWidgetState();
}
class _CMyTitleWidgetState extends State{
@override
Widget build(BuildContext context) {
debugPrint('get title build');
return Text(
'${context.watch().val}',
);
}
}
把 _MyHomePageState 中 build 函数的 getTitle(context) 替换成 CMyTitleWidget()
...
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text('You have pushed the button this many times:'),
CMyTitleWidget(),//!!!替换这一行
],
),
),
...
启动并点击按钮打印如下:
flutter: home build
flutter: provider build
flutter: get title build
flutter: CMyModel:inited
flutter: CMyModel:inc invoked
flutter: get title build
刷新事件出现了!只会刷新发生变化的子树(向上的树结点不会刷新)
5. 把CMyModel改成如下:(增加一个新的属性:secVal)
class CMyModel extends ChangeNotifier{
late int val;
int secVal;
CMyModel(this.val,{this.secVal = 100}){
debugPrint('CMyModel:inited');
}
void inc(){
val++;
debugPrint('CMyModel:inc invoked');
notifyListeners();
}
void secInc(){
secVal += 2;
debugPrint('CMyModel:secInc invoked');
notifyListeners();
}
@override
void dispose(){
super.dispose();
debugPrint('CMyModel:disposed');
}
}
再创建一个新的类,用来显示它的值 secVal
class CMyTitleWidget2 extends StatefulWidget{
const CMyTitleWidget2({super.key});
@override
State createState()=>_CMyTitleWidgetState2();
}
class _CMyTitleWidgetState2 extends State{
@override
Widget build(BuildContext context) {
debugPrint('get title build.2');
return Text(
'${context.watch().secVal}',
);
}
}
把 _MyHomePageState 中 build 函数修改如下:
...
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text('You have pushed the button this many times:'),
CMyTitleWidget(),
CMyTitleWidget2(),
],
),
),
...
启动并运行,日志打印如下:
flutter: home build
flutter: provider build
flutter: get title build
flutter: CMyModel:inited
flutter: get title build.2
flutter: CMyModel:inc invoked
flutter: get title build.2
flutter: get title build
flutter: CMyModel:secInc invoked
flutter: get title build.2
flutter: get title build
2个按钮点击后都会导致 CMyTitleWidget 与 CMyTitleWidget2 刷新。
其实我们不希望这样!
6. 把 CMyTitleWidget 改进一下,用 Selector 来包含一层,希望可以过滤其中的内容,改动如下:
class _CMyTitleWidgetState extends State {
@override
Widget build(BuildContext context) {
debugPrint('get title build');
return Selector(
selector: (_, myModel) => myModel.val,
builder: (_, val, child) {
debugPrint('get title build.builder');
return Text(val.toString());
},
);
}
}
class _CMyTitleWidgetState2 extends State{
@override
Widget build(BuildContext context) {
debugPrint('get title build.2');
return Selector(
selector: (_, myModel) => myModel.secVal,
builder: (_, val, child) {
debugPrint('get title build.2.builder');
return Text(val.toString());
},
);
}
}
结果如下:
flutter: home build
flutter: provider build
flutter: get title build
flutter: CMyModel:inited
flutter: get title build.builder
flutter: get title build.2
flutter: get title build.2.builder
flutter: CMyModel:inc invoked
flutter: get title build.builder
flutter: CMyModel:secInc invoked
flutter: get title build.2.builder
只刷新我们预期的部分,完美!!!