Google2019I/O大会上被谷歌推荐,原本谷歌的provide被弃用,与大部分状态管理一样使用了InheritedWidget。基于Provider3.0
第二篇Flutter状态管理Provider(二)
Provider()
两种方式Provider()和Provider.value(),使用基本差不多,区别在于Provider()提供dispose参数,可以在传递一个方法销毁的时候被调用,方便StatelessWidget释放资源,使用Provider写一个bloc
1794647-cf4839d4dccb3bab_gaitubao_300x555.gif
import 'dart:async';
class CountBloc {
final StreamController<int> _countController = StreamController();
int count = 0;
Stream<int> stream;
CountBloc() {
stream = _countController.stream.asBroadcastStream();
}
add() {
_countController.add(++count);
}
//关闭
dispose() {
_countController?.close();
}
}
界面代码
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'count_bloc.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
//如果状态管理放在顶层 MaterialApp 之上,它的作用域是全局,任何界面都可以获取;
return Provider<CountBloc>(
builder: (context) => CountBloc(),
//dispose:在widget销毁的时候调用,方便关闭stream,可以防止内存泄露
//特别是在在StatelessWidget中使用非常好,因为StatelessWidget没有dispose方法
dispose: (context, value) => value.dispose(),
child: MaterialApp(
title: "provider",
home: HomePage(),
),
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("HomePage")),
body: StreamBuilder(
stream: Provider.of<CountBloc>(context).stream,
initialData: 0,
builder: (context, snapshot) {
return Center(child: Text("${snapshot.data}"));
}),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => SecondPage()));
},
child: Icon(Icons.arrow_forward_ios),
),
);
}
}
class SecondPage extends StatefulWidget {
@override
_SecondPageState createState() => _SecondPageState();
}
class _SecondPageState extends State<SecondPage> {
@override
Widget build(BuildContext context) {
CountBloc bloc = Provider.of<CountBloc>(context);
return Scaffold(
appBar: AppBar(title: Text("第二页")),
body: StreamBuilder(
stream: bloc.stream,
initialData: bloc.count,
builder: (context, snapshot) {
return Center(child: Text("${snapshot.data}"));
}),
floatingActionButton: FloatingActionButton(
onPressed: () => bloc.add(),
child: Icon(Icons.add),
),
);
}
}
- 下面使用ValueListenableProvider,它只支持单一数据的监听,有两种方式,一种ValueListenableProvider.value(),另一种ValueListenableProvider(),两种方式几乎是相同的。
先介绍下Consumer和Provider:
//此方法将从BuildContext关联的小部件树中查找,它将返回找到的最近的类型变量T
Provider.of<T>( BuildContext context,
{bool listen = true}//listen:默认true监听状态变化,false为不监听状态改变
)
//也可以使用Consumer组件获取,Consumer可用在没有context的地方,还可以优化性能
Consumer<T>({
@required this.builder,//这边写布局
this.child,//可以控制刷新性能优化,当数据数据发生改变,不会重新build,
})
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "provider",
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
ValueNotifier<int> count = ValueNotifier(0);
//在HomePage里面写状态,它的作用域只在HomePage中
return Scaffold(
appBar: AppBar(title: Text("home")),
body: ValueListenableProvider.value(
value: count,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
LeftView(), CenterView(), RightView()
],
),
),
floatingActionButton:
FloatingActionButton(onPressed: () => count.value += 1,child: Icon(Icons.add),),
);
}
}
class LeftView extends StatelessWidget {
@override
Widget build(BuildContext context) {
print("LeftView:build");
return Consumer<int>(
child: MyText(),
builder: (context, value, child) {
return Container(
width: 100,
height: 100,
color: Colors.blue,
alignment: Alignment.center,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[child, Text("$value")]));
});
}
}
class MyText extends StatelessWidget {
@override
Widget build(BuildContext context) {
print("MyText:build");
return Text("数量");
}
}
class CenterView extends StatelessWidget {
@override
Widget build(BuildContext context) {
print("CenterView:build");
return Container(
width: 100,
height: 100,
color: Colors.pink,
alignment: Alignment.center,
child: Text(
//listen: false 不监听状态改变
"数量\n${Provider.of<int>(context, listen: false)}",
textAlign: TextAlign.center,
),
);
}
}
class RightView extends StatelessWidget {
@override
Widget build(BuildContext context) {
print("RightView:build");
return Container(
width: 100,
height: 100,
color: Colors.green,
alignment: Alignment.center,
child: Text(
"数量\n${Provider.of<int>(context)}",
textAlign: TextAlign.center,
),
);
}
}
1794647-31a67f0a79b6b742_gaitubao_300x801.gif
1、观察日志发现蓝色LeftView和MyText初始化后没有重新build。
2、红色CenterView初始化后也没有重新build
3、绿色RightView会随着状态改变会重新build
总结使用Consumer可以有效的优化性能,使用ValueListenableProvider时Provider.of<T>()获取部件树中状态同时也可以监听状态改变从而刷新部件。
网友评论