Flutter状态管理Provider,简单上手
在之前的文章中介绍了 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 = ;
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依赖
provider: ^3.1.+
pub地址:https://pub.dev/packages/provider
第二步,创建Model
class Counter with ChangeNotifier {
int _count = ;
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(),
)
);
}
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 = ;
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();//
},
child: Icon(Icons.add),
),
);
}
}
效果图:



Flutter状态管理Provider,简单上手的更多相关文章
- Flutter 状态管理- 使用 MobX
文 / Paul Halliday, developer.school 创始人 众所周知,状态管理是每个软件项目都需要持续迭代更新的方向.它并不是一个「一次性」的工作, 而需要不断确保你遵循的最佳实践 ...
- Flutter状态管理之provide和provider的使用区别
说道状态管理不得不说谷歌的亲自开发的两款状态管理Widget:第一个是provide,第二个是provider. 这两个的区别就是一个出来的早,现在好像没整么更新了.第二个是2019才出来的目前的版本 ...
- Flutter | 状态管理特别篇——Provide
前言 今天偶然发现在谷歌爸爸的仓库下出现了一个叫做flutter-provide的状态管理框架,2月8日才第一次提交,非常新鲜.在简单上手之后感觉就是一个字--爽!所以今天就跟大家分享一下这个新的状态 ...
- Flutter 状态管理 flutter_Provide
项目的商品类别页面将大量的出现类和类中间的状态变化,这就需要状态管理.现在Flutter的状态管理方案很多,redux.bloc.state.Provide. Scoped Model : 最早的状态 ...
- Flutter 状态管理之BLoC
在正式介绍 BLoC之前, 为什么我们需要状态管理.如果你已经对此十分清楚,那么建议直接跳过这一节.如果我们的应用足够简单,Flutter 作为一个声明式框架,你或许只需要将 数据 映射成 视图 就可 ...
- Flutter 状态管理框架 Provider 和 Get 分析
文/ Nayuta,CFUG 社区 状态管理一直是 Flutter 开发中一个火热的话题.谈到状态管理框架,社区也有诸如有以 Get.Provider 为代表的多种方案,它们有各自的优缺点. 面对这么 ...
- VueX(vue状态管理)简单小实例
VueX:状态管理 Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化. 核心模块:State. ...
- Vue状态管理Vuex简单使用
状态管理保存在store\index.js中,简单说明如下 import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export def ...
- Vuex-全局状态管理【简单小案例】
前言: Vuex个人见解: 1.state :所有组件共享.共用的数据.理解为不是一个全局变量,不能直接访问以及操作它.2.mutations : 如何操作 state 呢?需要有一个能操作state ...
随机推荐
- jquery统计输入文字的个数并对其进行判断
<textarea placeholder="该产品满足你的期待吗?说说你的使用心得,分享给 同样看中的他们吧"></textarea> <span ...
- SIGAI机器学习第十五集 支持向量机2
讲授线性分类器,分类间隔,线性可分的支持向量机原问题与对偶问题,线性不可分的支持向量机原问题与对偶问题,核映射与核函数,多分类问题,libsvm的使用,实际应用 大纲: SVM求解面临的问题 SMO算 ...
- 动态menu导航条以及treeview树
1.menu表数据 2.在后台生成html内容后,前台利用nav-h.css生成menu导航条,利用Jquery的treeview插件生成menu树 前台coding: <!DOCTYPE ht ...
- jsp中submit的连接属性是什么?
把注册的按钮改成button:<form action="dologin.jsp" method="post">用户<input type=& ...
- js判断当前时区【TimeZone】是否是夏令时
var d1 = new Date(2009, 0, 1); var d2 = new Date(2009, 6, 1); if (d1.getTimezoneOffset() != d2.getTi ...
- [转] C++ STL中map.erase(it++)用法原理解析
总结一下map::erase的正确用法. 首先看一下在循环中使用vector::erase时我习惯的用法: for(vector<int>::iterator it = vecInt.be ...
- qt5.10 for android 使用webview时qml 与html 中js的相互访问
webview 本身没有qwebchannel 的接口,只能通过WebSocketServer 间接的访问. 参考 https://stackoverflow.com/questions/513131 ...
- testdisk修复磁盘文件
使用testdisk,分析之后,使用:P ,list文件,然后使用如下方法恢复文件 Use Right to change directory, h to hide Alternate Data St ...
- 《论文翻译》Xception
目录 深度可分离网络-Xception 注释 1. 摘要 2. 介绍 3. Inception假设 4. 卷积和分离卷积之间的联系 4. 先验工作 5. Xception 架构 6. 个人理解 单词汇 ...
- 2019暑期金华集训 Day1 组合计数
自闭集训 Day1 组合计数 T1 \(n\le 10\):直接暴力枚举. \(n\le 32\):meet in the middle,如果左边选了\(x\),右边选了\(y\)(且\(x+y\le ...