在之前的文章中介绍了 Google 官方仓库下的一个状态管理 Provide。乍一看这俩玩意可能很容易就被认为是同一个东西,仔细一看,这不就差了一个字吗,有什么区别呢。
首先,你要知道的最大的一个区别就是,Provide 被 Provider 干掉了...假如你就是用了 Provide 的,你的内心应该已经开始骂了,这不是坑爹吗 。不过幸运的是,你要从 Provide 迁移到 Provider 并不是太难。
Provider 从名字上就很容易理解,它就是用于提供数据,无论是在单个页面还是在整个 app 都有它自己的解决方案,我们可以很方便的管理状态。可以说,Provider 的目标就是完全替代StatefulWidget。
Provider非全局状态管理:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('搜索结果'),
),
body: Provider<String>.value( //provider
value: 'This is from MyHomePage',
child: MyHomePage(),
),
);
}
}
//Provider.of
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Text('${Provider.of<String>(context)}'),
);
}
}
//Consumer同样实现
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
//child: Text('${Provider.of<String>(context)}'),
child:Consumer<String>(builder:(context, data, child){
return Text(data);
}),
);
}
}
官方示例代码:
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class Counters with ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
class ProviderPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(builder: (_) => Counters()),
],
child: Consumer<Counters>(
builder: (context, counter, _) {
return MaterialApp(
supportedLocales: const [Locale('en')],
localizationsDelegates: [
DefaultMaterialLocalizations.delegate,
DefaultWidgetsLocalizations.delegate,
_ExampleLocalizationsDelegate(counter.count),
],
home: const MyHomePage(),
);
},
),
);
}
}
class ExampleLocalizations {
static ExampleLocalizations of(BuildContext context) =>
Localizations.of<ExampleLocalizations>(context, ExampleLocalizations);
const ExampleLocalizations(this._count);
final int _count;
String get title => 'Tapped $_count times';
}
class _ExampleLocalizationsDelegate
extends LocalizationsDelegate<ExampleLocalizations> {
const _ExampleLocalizationsDelegate(this.count);
final int count;
@override
bool isSupported(Locale locale) => locale.languageCode == 'en';
@override
Future<ExampleLocalizations> load(Locale locale) =>
SynchronousFuture(ExampleLocalizations(count));
@override
bool shouldReload(_ExampleLocalizationsDelegate old) => old.count != count;
}
class MyHomePage extends StatelessWidget {
const MyHomePage({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Title()),
body: const Center(child: CounterLabel()),
floatingActionButton: const IncrementCounterButton(),
);
}
}
class IncrementCounterButton extends StatelessWidget {
const IncrementCounterButton({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return FloatingActionButton(
onPressed: () {
// `listen: false` is specified here because otherwise that would make
// `IncrementCounterButton` rebuild when the counter updates.
Provider.of<Counters>(context, listen: false).increment();
},
tooltip: 'Increment',
child: const Icon(Icons.add),
);
}
}
class CounterLabel extends StatelessWidget {
const CounterLabel({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
final counter = Provider.of<Counters>(context);
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'${counter.count}',
style: Theme.of(context).textTheme.display1,
),
RaisedButton(
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context)=>ProviderSecond()));
},
child: Text('下一页'),
)
],
);
}
}
class Title extends StatelessWidget {
const Title({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Text(ExampleLocalizations.of(context).title);
}
}
class ProviderSecond extends StatelessWidget {
const ProviderSecond({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
final counter = Provider.of<Counters>(context);
return Scaffold(
appBar: AppBar(
leading: IconButton( //返回按钮
onPressed: (){
Navigator.pop(context); //返回上级页面
},
icon: Icon(Icons.arrow_back),
),
title: Text('第二页'),
),
body: Text(
'${counter.count}',
style: Theme.of(context).textTheme.display1,
),
);
}
}
效果图:
点击+到7,然后点击下一页,下一页的内容同样是7。
Provider2.0到3.0的改变:
2.0:
ChangeNotifierProvider.value(notifier: myNotifier),
StreamProvider(builder: (_) => StreamController<int>()),
3.0:
ChangeNotifierProvider.value(value: myNotifier),
StreamProvider.controller(builder: (_) => StreamController<int>()),
下面基于Provider v-3.0 写个简单的示例:
第一步,添加Provider依赖
provider: ^3.1.0+1
pub地址:https://pub.dev/packages/provider
第二步,创建Model
class Counter with ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
简单的一个Counters
对象,里面只有一个字段_count
- 这里需要混入
ChangeNotifier
- 写一个增加的方法,然后需要调用
notifyListeners();
这个方法是通知用到Counters
对象的widget刷新用的。 get
方法
第三步,使用ChangeNotifierProvider
我们要监听改变要在MyApp()外面套一层,这个是全局的,于是代码如下 :
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import './provider/counter.dart';
void main() {
//runApp(new MyApp());
runApp(
ChangeNotifierProvider<Counter>.value(//ChangeNotifierProvider调用value()方法,里面传出value和child
value: Counter(),//value设置了默认的Counter()
child: MyApp(),
)
);
}
当然Provider不止提供了ChangeNotifierProvider
,还有Provider、
ListenableProvider、
ValueListenableProvider
、StreamProvider
,
具体可以看wiki.
如果想管理多个对象可以用MultiProvider
,如下:
void main() {
//runApp(new MyApp());
runApp(
// ChangeNotifierProvider<Counter>.value(//ChangeNotifierProvider调用value()方法,里面传出value和child
// value: Counter(),//value设置了默认的Counter()
// child: MyApp(),
// )
MultiProvider(
providers: [
ChangeNotifierProvider.value(value: Counter()),
//ChangeNotifierProvider(builder: (_) => Counter()),
],
child: MyApp(),
),
);
}
第四步,使用Provider获取Counter的值
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../provider/counter.dart';
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Home"),
actions: <Widget>[
FlatButton(
child: Text("下一页"),
onPressed: () =>
Navigator.push(context, MaterialPageRoute(builder: (context) {
return SecondPage();
})),
),
],
),
body: Center(
child: Text("${Provider.of<Counter>(context).count}"),//用Provider.of<Counter>(context).count获取_count的值,Provider.of<T>(context)相当于Provider去查找它管理的Counter()
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Provider.of<Counter>(context).increment();//用Provider.of<Counter>(context).increment();调用Counter()中的increment()方法
},
child: Icon(Icons.add),
),
);
}
}
同样第二个页面也这样写,如下
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
var counter = Provider.of<Counter>(context).count;
return Scaffold(
appBar: AppBar(
title: Text("SecondPage"),
),
body: Center(
child: Text("${counter}"),
//child: Text("${Provider.of<Counter>(context).count}"),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Provider.of<Counter>(context).increment();
},
child: Icon(Icons.add),
),
);
}
}
这样,当每个页面都点击+号按钮时,_count
便会+1,同时通知并更新到使用它的地方。
完整代码写到一个页面,copy后可直接运行:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
main() {
runApp(ChangeNotifierProvider<Counter>.value(
value: Counter(),
child: MyApp(),
));
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Provider",
home: HomePage(),
);
}
}
class Counter with ChangeNotifier {//混入ChangeNotifier
int _count = 0;
get count => _count;
void increment() {
_count++;
notifyListeners();//通知
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Home"),
actions: <Widget>[
FlatButton(
child: Text("下一页"),
onPressed: () =>
Navigator.push(context, MaterialPageRoute(builder: (context) {
return SecondPage();
})),
),
],
),
body: Center(
child: Text("${Provider.of<Counter>(context).count}"),//用Provider.of<Counter>(context).count获取_count的值,Provider.of<T>(context)相当于Provider去查找它管理的Counter()
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Provider.of<Counter>(context).increment();//用Provider.of<Counter>(context).increment();调用Counter()中的increment()方法
},
child: Icon(Icons.add),
),
);
}
}
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
var counter = Provider.of<Counter>(context).count;
return Scaffold(
appBar: AppBar(
title: Text("SecondPage"),
),
body: Center(
child: Text("${counter}"),
//child: Text("${Provider.of<Counter>(context).count}"),//1
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Provider.of<Counter>(context).increment();//2
},
child: Icon(Icons.add),
),
);
}
}
效果图:
来源:oschina
链接:https://my.oschina.net/u/4345306/blog/4303546