当前位置: 首页 > news >正文

【Flutter】状态管理:Provider状态管理

在 Flutter 开发中,状态管理是一个至关重要的部分。随着应用的规模和复杂性增加,简单的局部状态管理(如 setState()InheritedWidget)可能变得难以维护和扩展。Provider 是一种推荐的、广泛使用的 Flutter 状态管理工具,它能够帮助我们更轻松地管理应用中复杂的全局状态,并且具有高效、易于使用的特性。

本教程将详细介绍如何使用 Provider 来管理 Flutter 应用中的状态,内容包括 ChangeNotifierConsumer 的基本用法,以及如何使用 MultiProviderProxyProvider 来管理复杂的状态依赖关系。

什么是 Provider

Provider 是一个 Flutter 的状态管理库,它简化了状态的共享与管理。与传统的状态管理相比,Provider 更加简洁,提供了一种通过依赖注入(Dependency Injection)将状态传递给组件树的方式,而不需要手动传递状态。

主要的概念包括:

  • ChangeNotifier:一个用于通知监听器状态发生变化的类。它是最常见的 Provider 使用方式。
  • Consumer:一个用于监听并响应状态变化的 widget。
  • MultiProvider:用于同时提供多个 Provider 的工具。
  • ProxyProvider:用于处理多个 Provider 之间的依赖关系。

Provider 的基础使用

安装 Provider

首先,我们需要在 pubspec.yaml 文件中添加 provider 包依赖:

dependencies:flutter:sdk: flutterprovider: ^6.0.0

运行命令 flutter pub get 安装依赖。

ChangeNotifierChangeNotifierProvider

ChangeNotifierProvider 中最常用的状态管理工具。它提供了一种简单的机制来监听状态的变化,并通知所有依赖该状态的组件进行重新构建。

ChangeNotifierProvider 是用于在应用中提供一个 ChangeNotifier 实例的 Provider

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';// 定义 ChangeNotifier 类,用于管理计数器状态
class Counter with ChangeNotifier {int _count = 0;int get count => _count;void increment() {_count++;notifyListeners();  // 通知所有监听器,状态已经更新}
}void main() {runApp(// 使用 ChangeNotifierProvider 提供状态ChangeNotifierProvider(create: (context) => Counter(),child: MyApp(),),);
}class MyApp extends StatelessWidget {Widget build(BuildContext context) {return MaterialApp(home: CounterPage(),);}
}class CounterPage extends StatelessWidget {Widget build(BuildContext context) {// 使用 Consumer 监听 Counter 状态并更新 UIreturn Scaffold(appBar: AppBar(title: Text('Provider Example'),),body: Center(child: Consumer<Counter>(builder: (context, counter, child) {return Text('Counter: ${counter.count}',style: Theme.of(context).textTheme.headline4,);},),),floatingActionButton: FloatingActionButton(onPressed: () {// 通过 Provider 获取 Counter 实例并调用 incrementProvider.of<Counter>(context, listen: false).increment();},child: Icon(Icons.add),),);}
}

代码详解

  1. Counter:它继承了 ChangeNotifier,内部定义了一个私有变量 _count 和对应的 get 方法 count,同时通过 increment() 方法改变状态并调用 notifyListeners() 通知所有依赖该状态的组件。

  2. ChangeNotifierProvider:它包装了 MyApp 并提供了 Counter 的实例。create 方法用于在组件树的最顶层创建并提供一个 Counter 实例。

  3. Consumer:它用于订阅 Counter 的状态变化。当状态变化时,Consumer 会自动重建其子组件并更新界面。builder 回调提供了当前的状态(即 Counter 实例)。

  4. Provider.of<Counter>(context):用于获取 Counter 实例。通过 listen: false,我们确保该调用不会引起组件的重建,只是简单调用 increment() 来更新状态。

使用 MultiProvider 管理多个状态

在一个复杂的应用中,我们可能需要管理多个独立的状态。例如,一个应用中既有用户信息的状态,也有购物车状态。为了简化多个 Provider 的管理,Flutter 提供了 MultiProvider,允许我们在一个地方声明多个 Provider

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';// 用户信息状态
class UserInfo with ChangeNotifier {String _name = 'John Doe';String get name => _name;void updateName(String newName) {_name = newName;notifyListeners();}
}// 购物车状态
class Cart with ChangeNotifier {int _items = 0;int get items => _items;void addItem() {_items++;notifyListeners();}
}void main() {runApp(MultiProvider(providers: [ChangeNotifierProvider(create: (context) => UserInfo()),ChangeNotifierProvider(create: (context) => Cart()),],child: MyApp(),),);
}class MyApp extends StatelessWidget {Widget build(BuildContext context) {return MaterialApp(home: HomePage(),);}
}class HomePage extends StatelessWidget {Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('MultiProvider Example'),),body: Column(mainAxisAlignment: MainAxisAlignment.center,children: [Consumer<UserInfo>(builder: (context, userInfo, child) {return Text('User: ${userInfo.name}');},),Consumer<Cart>(builder: (context, cart, child) {return Text('Items in cart: ${cart.items}');},),],),floatingActionButton: FloatingActionButton(onPressed: () {Provider.of<Cart>(context, listen: false).addItem();},child: Icon(Icons.add),),);}
}

代码详解

  1. UserInfoCart:分别表示用户信息和购物车的状态,它们都继承自 ChangeNotifier

  2. MultiProvider:用于一次性提供多个 ChangeNotifier。通过 providers 参数,我们可以同时提供 UserInfoCart 的状态。

  3. Consumer:两个 Consumer 分别监听 UserInfoCart 的状态变化,并更新界面。

通过 MultiProvider,我们能够更简洁地管理多个状态,并且保持代码的可读性和可维护性。

使用 ProxyProvider 处理状态依赖

在一些场景中,不同的 Provider 之间可能存在依赖关系。例如,购物车状态可能依赖于用户状态。为了管理这种复杂的状态依赖关系,Flutter 提供了 ProxyProvider

ProxyProvider 允许一个 Provider 的实例依赖于其他 Provider,并根据这些依赖动态创建新的状态。

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';// 用户信息状态
class UserInfo with ChangeNotifier {String _name = 'John Doe';String get name => _name;void updateName(String newName) {_name = newName;notifyListeners();}
}// 订单状态,依赖于用户信息
class Order {final String userName;Order(this.userName);
}void main() {runApp(MultiProvider(providers: [ChangeNotifierProvider(create: (context) => UserInfo()),ProxyProvider<UserInfo, Order>(update: (context, userInfo, previousOrder) =>Order(userInfo.name),),],child: MyApp(),),);
}class MyApp extends StatelessWidget {Widget build(BuildContext context) {return MaterialApp(home: OrderPage(),);}
}class OrderPage extends StatelessWidget {Widget build(BuildContext context) {final order = Provider.of<Order>(context);return Scaffold(appBar: AppBar(title: Text('ProxyProvider Example'),),body: Center(child: Text('Order for user: ${order.userName}'),),);}
}

代码详解

  1. UserInfo:管理用户信息。

  2. Order:订单类,它依赖于 UserInfo,即每个订单都与用户关联。

  3. ProxyProvider:用于处理 Order 依赖 UserInfo 的场景。update 方法会在 UserInfo 变化时重新创建 Order 实例。

总结

通过学习 Provider,你已经掌握了 Flutter 中一种强大的全局状态管理工具。Provider 可以帮助你轻松实现跨组件状态共享、复杂状态依赖管理,并且保持代码的简洁性和可维护性。

相关文章:

【Flutter】状态管理:Provider状态管理

在 Flutter 开发中&#xff0c;状态管理是一个至关重要的部分。随着应用的规模和复杂性增加&#xff0c;简单的局部状态管理&#xff08;如 setState() 和 InheritedWidget&#xff09;可能变得难以维护和扩展。Provider 是一种推荐的、广泛使用的 Flutter 状态管理工具&#x…...

来个Oracle一键检查

启停、切换、升级、网络改造等场景下&#xff0c;需要对数据库有些基本检查操作&#xff0c;确认当前是否运行正常&#xff0c;主打一个简单和一键搞定。 #!/bin/bash## 实例个数 告警日志 实例状态 会话 活动会话 锁 集群状态 服务状态 磁盘空间 侦听日志 ## linux vmstat 2 …...

C语言中的分支与循环(中 1)

关系操作符 C语言用于比较的表达式&#xff0c;称为"关系表达式"&#xff0c;里面使用的运算符称为关系运算符&#xff0c;关系运算符主要有以下6类。 > 大于运算符< 小于运算符>大于等于运算符< 小于等于运算符 相等运算符! 不相等运算符 下面是例子:…...

Git_GitLab

Git_GitLab 安装 服务器准备 安装包准备 编写安装脚本 初始化 GitLab 服务 启动 GitLab 服务 浏览器访问 GitLab GitLab 创建远程库 IDEA 集成 GitLab 安装 GitLab 插件 设置 GitLab 插件 安装 服务器准备 准备一个系统为 CentOS7 以上版本的服务器&#xff0c;使…...

如何自定义一个自己的 Spring Boot Starter 组件(从入门到实践)

文章目录 一、什么是 Spring Boot Starter&#xff1f;二、为什么要自定义 Starter&#xff1f;三、自定义 Starter 的基本步骤1. 创建 Maven 项目2. 配置 pom.xml3. 创建自动配置类4. 创建业务逻辑类5. 创建 spring.factories 四、使用自定义 Starter五、总结推荐阅读文章 在使…...

CSS伪元素以及伪类和CSS特性

伪元素&#xff1a;可以理解为假标签。 有2个伪元素 &#xff08;1&#xff09;::before &#xff08;2&#xff09;::after ::before <!DOCTYPE html> <html> <head><title></title><style type"text/css">body::before{con…...

【论文笔记】Instantaneous Perception of Moving Objects in 3D

原文链接&#xff1a;https://arxiv.org/abs/2405.02781 简介&#xff1a;本文主张自动驾驶中细微运动的瞬时检测和量化与一般的大型运动同等重要。具体来说&#xff0c;由于激光雷达点云缺乏帧间对应关系&#xff0c;静态物体可能看起来在运动&#xff08;称为游泳效应&#x…...

Segugio:一款针对恶意软件的进程执行跟踪与安全分析工具

关于Segugio Segugio是一款功能强大的恶意软件安全分析工具&#xff0c;该工具允许我们轻松分析恶意软件执行的关键步骤&#xff0c;并对其进行跟踪分析和安全审计。 Segugio允许执行和跟踪恶意软件感染过程中的关键步骤&#xff0c;其中包括从点击第一阶段到提取恶意软件的最…...

互联网系统的微观与宏观架构

互联网系统的架构设计&#xff0c;通常会根据项目的体量、业务场景以及技术需求被划分为微观架构&#xff08;Micro-Architecture&#xff09;和宏观架构&#xff08;Macro-Architecture&#xff09;。这两者的概念与职责既独立又相互关联。本文将通过一些系统案例&#xff0c;…...

数据库、数据仓库、数据湖和数据中台有什么区别

很多企业在面对数据存储和管理时不知道如何选择合适的方式&#xff0c;数据库、数据仓库、数据湖和数据中台&#xff0c;这些方式都是什么&#xff1f;有什么样的区别&#xff1f;企业根据其业务类型该选择哪一种&#xff1f;本文就针对这些问题&#xff0c;来探讨下这些方式都…...

vscode配色主题与图标库推荐

vscode配色主题推荐:Andromedavsocde图标库&#xff1a; vscode-icons Andromeda Dark theme with a taste of the universe 仙女座&#xff1a;一套宇宙深空体验的哑暗色主题; 高对比度,色彩饱和; Easy Installation Open the extensions sidebar on Visual Studio CodeSear…...

深度学习模型入门教程:从基础到应用

深度学习模型入门教程&#xff1a;从基础到应用 前言 在人工智能的浪潮中&#xff0c;深度学习作为一种强大的技术&#xff0c;正在各行各业中发挥着越来越重要的作用。从图像识别到自然语言处理&#xff0c;深度学习正在改变我们的生活和工作方式。本文将带您深入了解深度学…...

数据结构 软考

算法具有5个特性 可行性&#xff0c;有限性&#xff0c;确定性&#xff0c;输入, 输出 图: 有向图 Kruskal(克鲁斯卡尔)算法 和 prim(普鲁姆)算法 都是贪心算法 是一种用来在加权连通图中寻找最小生成树的算法,其操作对象是边. 找最小的不形成环 1.哈夫曼树(也叫最优树)…...

colcon构建ros2功能包时,出现exited with code 2报错的解决方案(bug)

背景&#xff1a; 在学习ros2时&#xff0c;跟着别人的示例进行构建&#xff0c;手敲的代码难免有一些语法错误。 问题&#xff1a; 在colcon构建时&#xff0c;并不会直接输出语法报错。而是出现exited with code 2错误&#xff0c;并提示未能生成功能包&#xff0c;就算加入…...

【大模型LLM面试合集】大语言模型架构_位置编码

位置编码 1.位置编码 不同于RNN、CNN等模型&#xff0c;对于Transformer模型来说&#xff0c;位置编码的加入是必不可少的&#xff0c;因为纯粹的Attention模块是无法捕捉输入顺序的&#xff0c;即无法区分不同位置的Token。为此我们大体有两个选择&#xff1a; 想办法将位置…...

FLINK 分流

在Apache Flink中&#xff0c;分流&#xff08;Stream Splitting&#xff09;是指将一条数据流拆分成完全独立的两条或多条流的过程。这通常基于一定的筛选条件&#xff0c;将符合条件的数据拣选出来并放入对应的流中。以下是关于Flink分流的详细解释&#xff1a; 一、分流方式…...

从零开始:构建一个高效的开源管理系统——使用 React 和 Ruoyi-Vue-Plus 的实战指南

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…...

windows下pycharm社区版2024下载与安装(包含新建第一个工程)

windows下pycharm社区版2024下载与安装 下载pycharm pycharm官网 安装pycharm 1.进入官网 pycharm官网 下载 点击Download–>右侧Other versions 下载对应的社区版&#xff08;如下图&#xff09;&#xff1a;下载网址 2.点击运行下载好的安装包 点击下一步 3.更改pychar…...

重构案例:将纯HTML/JS项目迁移到Webpack

我们已经了解了许多关于 Webpack 的知识&#xff0c;但要完全熟练掌握它并非易事。一个很好的学习方法是通过实际项目练习。当我们对 Webpack 的配置有了足够的理解后&#xff0c;就可以尝试重构一些项目。本次我选择了一个纯HTML/JS的PC项目进行重构&#xff0c;项目位于 GitH…...

表格编辑demo

<el-form :model"form" :rules"status ? rules : {}" ref"form" class"form-container" :inline"true"><el-table :data"tableData"><el-table-column label"计算公式"><templat…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作&#xff0c;无需更改相机配置。但是&#xff0c;一…...

FastAPI 教程:从入门到实践

FastAPI 是一个现代、快速&#xff08;高性能&#xff09;的 Web 框架&#xff0c;用于构建 API&#xff0c;支持 Python 3.6。它基于标准 Python 类型提示&#xff0c;易于学习且功能强大。以下是一个完整的 FastAPI 入门教程&#xff0c;涵盖从环境搭建到创建并运行一个简单的…...

【网络安全产品大调研系列】2. 体验漏洞扫描

前言 2023 年漏洞扫描服务市场规模预计为 3.06&#xff08;十亿美元&#xff09;。漏洞扫描服务市场行业预计将从 2024 年的 3.48&#xff08;十亿美元&#xff09;增长到 2032 年的 9.54&#xff08;十亿美元&#xff09;。预测期内漏洞扫描服务市场 CAGR&#xff08;增长率&…...

LLM基础1_语言模型如何处理文本

基于GitHub项目&#xff1a;https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken&#xff1a;OpenAI开发的专业"分词器" torch&#xff1a;Facebook开发的强力计算引擎&#xff0c;相当于超级计算器 理解词嵌入&#xff1a;给词语画"…...

让AI看见世界:MCP协议与服务器的工作原理

让AI看见世界&#xff1a;MCP协议与服务器的工作原理 MCP&#xff08;Model Context Protocol&#xff09;是一种创新的通信协议&#xff0c;旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天&#xff0c;MCP正成为连接AI与现实世界的重要桥梁。…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件&#xff0c;这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下&#xff0c;实现高效测试与快速迭代&#xff1f;这一命题正考验着…...

LeetCode - 199. 二叉树的右视图

题目 199. 二叉树的右视图 - 力扣&#xff08;LeetCode&#xff09; 思路 右视图是指从树的右侧看&#xff0c;对于每一层&#xff0c;只能看到该层最右边的节点。实现思路是&#xff1a; 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...

【Linux】Linux 系统默认的目录及作用说明

博主介绍&#xff1a;✌全网粉丝23W&#xff0c;CSDN博客专家、Java领域优质创作者&#xff0c;掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围&#xff1a;SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...

怎么让Comfyui导出的图像不包含工作流信息,

为了数据安全&#xff0c;让Comfyui导出的图像不包含工作流信息&#xff0c;导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo&#xff08;推荐&#xff09;​​ 在 save_images 方法中&#xff0c;​​删除或注释掉所有与 metadata …...

论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing

Muffin 论文 现有方法 CRADLE 和 LEMON&#xff0c;依赖模型推理阶段输出进行差分测试&#xff0c;但在训练阶段是不可行的&#xff0c;因为训练阶段直到最后才有固定输出&#xff0c;中间过程是不断变化的。API 库覆盖低&#xff0c;因为各个 API 都是在各种具体场景下使用。…...