Flutter提供者模式说明

2023-10-26

在本文中,我们将介绍Flutter中的Provider模式。 Google的工作小组建议使用提供程序模式。 他们还在Flutter的Pragmatic State Management中的 Google I / O 2019上进行了介绍。

其他一些模式(例如BLoC体系结构)在内部使用提供程序模式。 但是提供者模式要容易得多,并且样板代码少得多。

在本文中,我们将使用flutter提供的默认Counter应用,并将其重构为使用Provider Pattern。

注意:如果您想学习BLoC架构,请在此处查看。

创建一个新的flutter项目,并根据需要命名。

首先,我们需要删除所有注释,以便我们可以处理所有内容。

 import 'package:flutter/material.dart' ;  void main() { 
   runApp(MyApp());  }  MyApp class extends StatelessWidget { 
   // This widget is the root of your application. 
   @override 
   Widget build(BuildContext context) { 
     return MaterialApp( 
       title: 'Flutter Demo' , 
       theme: ThemeData( 
         primarySwatch: Colors.blue, 
         visualDensity: VisualDensity.adaptivePlatformDensity, 
       ), 
       home: MyHomePage(title: 'Flutter Demo Home Page' ), 
     ); 
   }  }  class MyHomePage extends StatefulWidget { 
   MyHomePage({Key key, this .title}) : super (key: key); 
   final String title; 
   @override 
   _MyHomePageState createState() => _MyHomePageState();  }  class _MyHomePageState extends State<MyHomePage> { 
   int _counter = 0 ; 
   void _incrementCounter() { 
     setState(() { 
       _counter++; 
     }); 
   } 
   @override 
   Widget build(BuildContext context) { 
     return Scaffold( 
       appBar: AppBar( 
         title: Text(widget.title), 
       ), 
       body: Center( 
         child: Column( 
           mainAxisAlignment: MainAxisAlignment.center, 
           children: <Widget>[ 
             Text( 
               'You have pushed the button this many times:' , 
             ), 
             Text( 
               '$_counter' , 
               style: Theme.of(context).textTheme.headline4, 
             ), 
           ], 
         ), 
       ), 
       floatingActionButton: FloatingActionButton( 
         onPressed: _incrementCounter, 
         tooltip: 'Increment' , 
         child: Icon(Icons.add), 
       ), 
     ); 
   }  } 

现在,在pubspec.yaml文件中添加Provider的依赖 。 在我写作本书的时候,最新的版本是4.1.2这是你的pubspec.yaml会是什么样子:

 name: provider_pattern_explained  description: A new Flutter project.  publish_to: 'none'  version: 1.0 . 0 + 1  environment: 
   sdk: ">=2.7.0 <3.0.0"  dependencies: 
   flutter: 
     sdk: flutter 
   provider: ^ 4.1 . 2 
   cupertino_icons: ^ 0.1 . 3  dev_dependencies: 
   flutter_test: 
     sdk: flutter  flutter: 
   uses-material-design: true 

默认的应用程序基本上是一个有状态的小部件,每当您单击FloatingActionButton (调用setState ())时,该小部件都会重新生成。

但是,我们将其转换为无状态小部件!

让我们继续创建我们的提供商。 这将是我们应用程序的唯一事实来源。 这是我们存储状态的地方,在这种情况下,这是当前计数。

因此,创建一个名为Counter的类并添加count变量。

 import 'package:flutter/material.dart' ;  class Counter { 
   var _count = 0 ;  } 

要将其转换为提供程序类,请从material.dart包的ChangeNotifier中进行扩展。 这为我们提供了notifyListeners ()方法。 每当我们更改值时,这将通知所有侦听器。

由于我们在这里所做的只是增加计数器,因此添加一种增加计数器的方法。

 import 'package:flutter/material.dart' ;  class Counter extends ChangeNotifier { 
   var _count = 0 ; 
   void incrementCounter() { 
     _count += 1 ; 
   }  } 

在此方法的最后,我们将调用notifyListeners()。 这将触发整个应用程序对正在监听的小部件的更改。 这就是扑扑中提供者模式的美。 您不必在意手动分派到流。

还创建一个getter以返回计数器值。 我们将使用它来显示最新值。

 import 'package:flutter/material.dart' ;  class Counter extends ChangeNotifier { 
   var _count = 0 ; 
   int get getCounter { 
     return _count; 
   } 
   void incrementCounter() { 
     _count += 1 ; 
     notifyListeners(); 
   }  } 

现在我们有了提供程序的设置,我们可以继续在主窗口小部件中使用它了。

首先,让MyHomePage小部件转换为无状态小部件,而不是有状态小部件。 我们必须删除setState()调用,因为该调用仅在StatefulWidget中可用。

 import 'package:flutter/material.dart' ;  void main() { 
   runApp(MyApp());  }  MyApp class extends StatelessWidget { 
   @override 
   Widget build(BuildContext context) { 
     return MaterialApp( 
       title: 'Flutter Demo' , 
       theme: ThemeData( 
         primarySwatch: Colors.blue, 
         visualDensity: VisualDensity.adaptivePlatformDensity, 
       ), 
       home: MyHomePage(title: 'Flutter Demo Home Page' ), 
     ); 
   }  }  class MyHomePage extends StatelessWidget { 
   int _counter = 0 ; 
   final String title; 
   MyHomePage({ this .title}); 
   void _incrementCounter() {} 
   @override 
   Widget build(BuildContext context) { 
     return Scaffold( 
       appBar: AppBar( 
         title: Text(title), 
       ), 
       body: Center( 
         child: Column( 
           mainAxisAlignment: MainAxisAlignment.center, 
           children: <Widget>[ 
             Text( 
               'You have pushed the button this many times:' , 
             ), 
             Text( 
               '$_counter' , 
               style: Theme.of(context).textTheme.headline4, 
             ), 
           ], 
         ), 
       ), 
       floatingActionButton: FloatingActionButton( 
         onPressed: _incrementCounter, 
         tooltip: 'Increment' , 
         child: Icon(Icons.add), 
       ), 
     ); 
   }  } 

完成此操作后,现在我们可以在flutter中使用提供程序模式来设置和获取计数器值。 单击按钮后,我们需要将计数器值增加1。

因此,在_incrementCounter方法(按下按钮时调用)中添加以下行:

 Provider.of<Counter>(context, listen: false ).incrementCounter(); 

这里发生的事情是,您已要求Flutter进入Widget 并找到提供Counter的第一个位置(下一节将告诉您如何提供Counter)。 这就是Provider.of()所做的。

泛型( <>括号内的值)告诉flutter要查找的Provider类型是什么。 然后,颤动在小部件树上方向上移动,直到找到提供的值。 如果未在任何地方提供该值,则将引发异常。

最后,一旦有了提供程序,就可以在其上调用任何方法。 在这里,我们调用了递增计数方法。 但是我们还需要一个上下文,因此我们接受上下文作为参数,并更改onPressed方法以传递上下文:

 void _incrementCounter(BuildContext context) { 
   Provider.of<Counter>(context, listen: false ).incrementCounter();  } 

注意:我们设置了listen:false,因为我们不需要在这里监听任何值。 我们只是调度要执行的动作。

波动中的提供者模式将寻找提供的最新值。 下图将帮助您更好地理解。

在此图中, 绿色对象A将可用于其下面的其余元素,即B,C,D,E,F。

现在假设我们要向应用程序添加一些功能,并创建另一个提供程序Z。E和F要求Z。 那么添加该功能的最佳位置是什么?

我们可以将其添加到根即。 在A以上。 这会起作用。

但这不是很有效。 Flutter将遍历上面的所有小部件,最后到达根目录。 如果您有非常长的小部件树(肯定会在生产应用程序中使用),那么将所有内容置于根下不是一个好主意。

相反,我们可以看看E和F的共同点是什么? 那就是C。因此,如果将Z放在E和F的上方,它将起作用。

但是,如果我们要添加E和F所需的另一个对象X ,该怎么办? 我们将再次执行相同的操作。 请注意树是如何继续生长的。

有一种更好的方法来管理它。 如果我们在一个级别上提供所有对象怎么办?

太棒了。 这就是我们最终将如何在flutter中实现我们的提供者模式。 我们将使用一种称为MultiProvider的东西,让我们在一个级别上声明多个提供者!

我们将获得MultiProvider来包装MaterialApp小部件:

 MyApp class extends StatelessWidget { 
   @override 
   Widget build(BuildContext context) { 
     return MultiProvider( 
       providers: [ 
         ChangeNotifierProvider.value( 
           value: Counter(), 
         ), 
       ], 
       child: MaterialApp( 
         title: 'Flutter Demo' , 
         theme: ThemeData( 
           primarySwatch: Colors.blue, 
           visualDensity: VisualDensity.adaptivePlatformDensity, 
         ), 
         home: MyHomePage(title: "AndroidVille Provider Pattern" ), 
       ), 
     ); 
   }  } 

这样,我们就为小部件树提供了提供程序,并且可以在树中此级别以下的任何位置使用它。

只剩下一件事了。 我们需要更新显示的值。 来做吧。

要更新文本,请在MyHomePage小部件的构建功能中获取提供程序。 我们将使用创建的getter获得最新的价值。

然后只需将此值添加到下面的文本小部件即可。 我们完成了! 这就是您最终的main.dart文件的样子:

 import 'package:flutter/material.dart' ;  import 'package:provider/provider.dart' ;  import 'package:provider_pattern_explained/counter.dart' ;  void main() { 
   runApp(MyApp());  }  MyApp class extends StatelessWidget { 
   @override 
   Widget build(BuildContext context) { 
     return MultiProvider( 
       providers: [ 
         ChangeNotifierProvider.value( 
           value: Counter(), 
         ), 
       ], 
       child: MaterialApp( 
         title: 'Flutter Demo' , 
         theme: ThemeData( 
           primarySwatch: Colors.blue, 
           visualDensity: VisualDensity.adaptivePlatformDensity, 
         ), 
         home: MyHomePage(title: "AndroidVille Provider Pattern" ), 
       ), 
     ); 
   }  }  class MyHomePage extends StatelessWidget { 
   final String title; 
   MyHomePage({ this .title}); 
   void _incrementCounter(BuildContext context) { 
     Provider.of<Counter>(context, listen: false ).incrementCounter(); 
   } 
   @override 
   Widget build(BuildContext context) { 
     var counter = Provider.of<Counter>(context).getCounter; 
     return Scaffold( 
       appBar: AppBar( 
         title: Text(title), 
       ), 
       body: Center( 
         child: Column( 
           mainAxisAlignment: MainAxisAlignment.center, 
           children: <Widget>[ 
             Text( 
               'You have pushed the button this many times:' , 
             ), 
             Text( 
               '$counter' , 
               style: Theme.of(context).textTheme.headline4, 
             ), 
           ], 
         ), 
       ), 
       floatingActionButton: FloatingActionButton( 
         onPressed: () => _incrementCounter(context), 
         tooltip: 'Increment' , 
         child: Icon(Icons.add), 
       ), 
     ); 
   }  } 

注意:在这种情况下,我们没有设置listen:false,因为我们想听计数值的任何更新。

结论

如果您想看看,我也将这个项目托管在GitHub上: https : //github.com/Ayusch/Flutter-Provider-Pattern 。 如果您在下面的评论部分遇到任何问题,请告诉我。

翻译自: https://www.javacodegeeks.com/2020/05/flutter-provider-pattern-explained.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Flutter提供者模式说明 的相关文章

随机推荐

  • 2020年总结:互联网思维下的工业软件开发

    2020年的年终总结像往年一样如期而至 今年是个特殊的年份 疫情爆发 全国人民众志成城 支援武汉 把武汉疫情完美控制 接下来经历了一个整年的抗疫生活 见证了一个个门店的倒下 站起 一个个公司申请破产 又一个个公司申请登记注册 这一个年 见证
  • fread函数解析

    fread函数解析 1 size t fread void buffer size t elementsize size t count FILE stream return fread s buffer SIZE MAX elements
  • 微信小程序纯css实现一个弹出的菜单

    1 实现效果 2 实现原理 animation动画 transform属性 rotateZ translate 3 实现代码
  • 必读:学习C语言编程的路线图

    学习C语言编程 可以丰富编程思维的训练和经验 以下是一些学习C语言编程的路线图 设置开发环境 在计算机上安装C编译器 GNU编译器集合 GCC 是一个流行的选择 适用于Windows macOS和Linux等各种操作系统 安装IDE编程环境
  • 数据清洗方法

    来源 我是码农 转载请保留出处和链接 本文链接 http www 54manong com id 1220 1 数据错误 脏数据或错误数据 比如 温度 2003 数据不正确 0 代表真实的0还是代表缺失 数据不一致 2 删除重复值 删除重复
  • Shell脚本——条件语句

    shell脚本 编程条件语句 条件测试 if语句 case分支语句 一 条件测试 1 1 Test命令 1 2 文件测试 1 3整数值比较 1 4字符串比较 1 5逻辑测试 二 if语句 2 1 单分支结构 2 2双分支结构 2 3多分支结
  • Eclipse 语言包下载

    1 登陆http www eclipse org babel downloads php 选择你的eclipse版本 2 找到IDE中文补丁包 INDIGO的地址如下 http download eclipse org technology
  • Maven(六) eclipse 使用Maven deploy命令部署构建到Nexus

    转载于 http blog csdn net jun55xiu article details 43051627 1 应用场景 SYS UTIL 系统工具 项目部署 构建成JAR包 SYS UTIL XXX jar 存储到Nexus私服上
  • spring boot 使用application.properties 进行外部配置

    application properties大家都不陌生 我们在开发的时候 经常使用它来配置一些可以手动修改而且不用编译的变量 这样的作用在于 打成war包或者jar用于生产环境时 我们可以手动修改环境变量而不用再重新编译 spring b
  • python里的pypi是干什么用的_【python工具篇】pip和pypi

    PyPI the Python Package Index The Python Package Index is a repository of software for the Python programming language T
  • HTTP中GET,POST和PUT的区别

    一 HTTP中定义了以下几种请求方法 1 GET 2 POST 3 PUT 4 DELETE 5 HEAD 6 TRACE 7 OPTIONS 二 各个方法介绍 1 GET方法 对这个资源的查操作 2 DELETE方法 对这个资源的删操作
  • 电脑检测不到第二个显示器的解决方法

    一般是因为显示适配器被失效了 右击开始菜单 选择 设备管理器 再选择 显示适配器 这时图标上一般会带上感叹号 右击后选择禁用 再选择启用就能检测到第二个显示器
  • 第一个跑马灯实验

    如何新建一个工程 1 打开工程模板 删除其他不重要的库文件 把main 函数里的内容删除 不用的外设固件库文件可以删掉 节省编译时间 rcc 时钟使能 usart 串口 复用映射 setbits 设置高电平 resetbits 低电平 2
  • 「PAT甲级真题解析」Advanced Level 1006 Sign In and Sign Out

    PAT Advanced Level Practice 1006 Sign In and Sign Out 如果对你有帮助 要点个赞让我知道喔 文章目录 问题分析 完整描述步骤 伪代码描述 完整提交代码 问题分析 题目给出一组学生进入机房的
  • 计量经济学及Stata应用 陈强 第八章自相关习题8.3

    8 3使用数据集gasoline dta估计美国1953 2004年的汽油需求函数 考虑如下回归 其中 被解释变量lgasq为人均汽油消费量的对数 解释变量lincome为人均收入的对数 lgasp为汽油价格指数的对数 lpnc为新车价格指
  • ROS建模仿真(1)-创建机器人模型

    ROS建模仿真 1 创建机器人模型 创建catkin creat pkg功能包 创建机器人描述文件 创建launch文件 创建catkin creat pkg功能包 创建机器人描述文件 创建launch文件 创建catkin creat p
  • Mac OS上使用ffmpeg的“血泪”总结

    标题真不是夸张 这几天在整理视频相关的处理流程 为了获得一些性能数据 打算在自己的MacBook Pro 上面装ffmepg 这一折腾4 5天就过去了 有些问题 在解决之后就豁然开朗了 没有解决之前 真的是百思不得其解 中间就好像隔着一层纱
  • AF_INET和AF_PACKET区别

    http blog csdn net kzm2008 article details 5372834 man 7 ip man 7 packet Packet sockets are used to receive or send raw
  • 单片机蓝桥杯——定时中断实现数码管显示、按键判断

    1 1ms定时中断T0 控制数码管显示 1 关于中断 关于定时中断的初始化函数可直接在STC ISP软件上生成 如下图所示 注意 初始化函数中并没有打开EA和ET0 需要自己加上 2 关于数码管显示 数码管段码 segCode 0 segC
  • Flutter提供者模式说明

    在本文中 我们将介绍Flutter中的Provider模式 Google的工作小组建议使用提供程序模式 他们还在Flutter的Pragmatic State Management中的 Google I O 2019上进行了介绍 其他一些模