? ? ? ?Google2019I/O大會上被谷歌推薦感挥,原本谷歌的provide被棄用缩搅,與大部分狀態(tài)管理一樣使用了InheritedWidget〈ビ祝基于Provider3.0
第二篇Flutter狀態(tài)管理Provider(二)
Provider()
兩種方式Provider()和Provider.value()硼瓣,使用基本差不多,區(qū)別在于Provider()提供dispose參數(shù)置谦,可以在傳遞一個方法銷毀的時候被調(diào)用堂鲤,方便StatelessWidget釋放資源,使用Provider寫一個bloc
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) {
//如果狀態(tài)管理放在頂層 MaterialApp 之上媒峡,它的作用域是全局瘟栖,任何界面都可以獲取;
return Provider<CountBloc>(
builder: (context) => CountBloc(),
//dispose:在widget銷毀的時候調(diào)用,方便關閉stream丝蹭,可以防止內(nèi)存泄露
//特別是在在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,它只支持單一數(shù)據(jù)的監(jiān)聽奔穿,有兩種方式镜沽,一種ValueListenableProvider.value(),另一種ValueListenableProvider()贱田,兩種方式幾乎是相同的缅茉。
先介紹下Consumer和Provider:
//此方法將從BuildContext關聯(lián)的小部件樹中查找,它將返回找到的最近的類型變量T
Provider.of<T>( BuildContext context,
{bool listen = true}//listen:默認true監(jiān)聽狀態(tài)變化男摧,false為不監(jiān)聽狀態(tài)改變
)
//也可以使用Consumer組件獲取蔬墩,Consumer可用在沒有context的地方,還可以優(yōu)化性能
Consumer<T>({
@required this.builder,//這邊寫布局
this.child,//可以控制刷新性能優(yōu)化耗拓,當數(shù)據(jù)數(shù)據(jù)發(fā)生改變拇颅,不會重新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里面寫狀態(tài)乔询,它的作用域只在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("數(shù)量");
}
}
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 不監(jiān)聽狀態(tài)改變
"數(shù)量\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(
"數(shù)量\n${Provider.of<int>(context)}",
textAlign: TextAlign.center,
),
);
}
}
1樟插、觀察日志發(fā)現(xiàn)藍色LeftView和MyText初始化后沒有重新build。
2竿刁、紅色CenterView初始化后也沒有重新build
3黄锤、綠色RightView會隨著狀態(tài)改變會重新build
總結使用Consumer可以有效的優(yōu)化性能,使用ValueListenableProvider時Provider.of<T>()獲取部件樹中狀態(tài)同時也可以監(jiān)聽狀態(tài)改變從而刷新部件食拜。