在之前的文章中介绍了 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 v-3.0 写个简单的示例: 

第一步,添加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

  1. 这里需要混入ChangeNotifier
  2. 写一个增加的方法,然后需要调用notifyListeners();这个方法是通知用到Counters对象的widget刷新用的。
  3. 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、ValueListenableProviderStreamProvider,
具体可以看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,简单上手的更多相关文章

  1. Flutter 状态管理- 使用 MobX

    文 / Paul Halliday, developer.school 创始人 众所周知,状态管理是每个软件项目都需要持续迭代更新的方向.它并不是一个「一次性」的工作, 而需要不断确保你遵循的最佳实践 ...

  2. Flutter状态管理之provide和provider的使用区别

    说道状态管理不得不说谷歌的亲自开发的两款状态管理Widget:第一个是provide,第二个是provider. 这两个的区别就是一个出来的早,现在好像没整么更新了.第二个是2019才出来的目前的版本 ...

  3. Flutter | 状态管理特别篇——Provide

    前言 今天偶然发现在谷歌爸爸的仓库下出现了一个叫做flutter-provide的状态管理框架,2月8日才第一次提交,非常新鲜.在简单上手之后感觉就是一个字--爽!所以今天就跟大家分享一下这个新的状态 ...

  4. Flutter 状态管理 flutter_Provide

    项目的商品类别页面将大量的出现类和类中间的状态变化,这就需要状态管理.现在Flutter的状态管理方案很多,redux.bloc.state.Provide. Scoped Model : 最早的状态 ...

  5. Flutter 状态管理之BLoC

    在正式介绍 BLoC之前, 为什么我们需要状态管理.如果你已经对此十分清楚,那么建议直接跳过这一节.如果我们的应用足够简单,Flutter 作为一个声明式框架,你或许只需要将 数据 映射成 视图 就可 ...

  6. Flutter 状态管理框架 Provider 和 Get 分析

    文/ Nayuta,CFUG 社区 状态管理一直是 Flutter 开发中一个火热的话题.谈到状态管理框架,社区也有诸如有以 Get.Provider 为代表的多种方案,它们有各自的优缺点. 面对这么 ...

  7. VueX(vue状态管理)简单小实例

    VueX:状态管理 Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化. 核心模块:State. ...

  8. Vue状态管理Vuex简单使用

    状态管理保存在store\index.js中,简单说明如下 import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export def ...

  9. Vuex-全局状态管理【简单小案例】

    前言: Vuex个人见解: 1.state :所有组件共享.共用的数据.理解为不是一个全局变量,不能直接访问以及操作它.2.mutations : 如何操作 state 呢?需要有一个能操作state ...

随机推荐

  1. guava字符串工具--------Joiner 根据给定的分隔符把字符串连接到一起

    public class JoinerTest { public static void main(String args[]){ //1.将list字符串集合,以,形式转为字符串 List<S ...

  2. Greenplum 查看表的分区键与分区类型

    方法一 查看表的分区键 select d.nspname||'.'||a.relname as table_name,string_agg(b.attname,',') as column_namef ...

  3. junit报错

    java.lang.RuntimeException: iwap 环境还没有初始化,请先调用IWapContext.init(). at com.nantian.ofpiwap.IWapContext ...

  4. vue+axios新手实践实现登陆

    vue+axios新手实践实现登陆 https://segmentfault.com/a/1190000015201803 增加 利用HTML5的history.replacestate()修改当前页 ...

  5. QVariantMap 和 QVariant

    typedef QVariantMap Synonym for(同义词) QMap<QString, QVariant>. QVariant类型的放入和取出必须是相对应的,你放入一个int ...

  6. snmp_trap/snmptt

    Zabbix Snmp Trap 配置 1. Zabbix Server 操作 1.1 Snmp Trap 安装配置 yum install -y net-snmp net-snmp-utils vi ...

  7. P3975 (后缀自动机sort)

    题目链接: https://www.luogu.org/problem/P3975 题意: 求出所有字串的第k大子串 有两种,第一种对于出现在不同位置的相同子串算作一个子串 第二种,对于不同位置的子串 ...

  8. .net core 资料网站 和 开源项目

    https://www.xcode.me/ 1.ASP.NET Core模块化前后端分离快速开发框架介绍之1.开篇 2.https://www.cnblogs.com/laozhang-is-phi/ ...

  9. 2018-2019-2 20165234 《网络对抗技术》 Exp7 网络欺诈防范

    Exp7  网络欺诈防范 实验内容 1. 简单应用SET工具建立冒名网站 2. ettercap DNS spoof 3. 结合应用两种技术,用DNS spoof引导特定访问到冒名网站 4. 请勿使用 ...

  10. OpenJudge计算概论-奇数求和

    /*=================================================== 奇数求和 总时间限制: 1000ms 内存限制: 65536kB 描述 计算非负整数 m 到 ...