当前位置: 首页 > 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…...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程&#xff1a;&#xff08;白话解释&#xff09; 我们将原始待发送的消息称为 M M M&#xff0c;依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)&#xff08;意思就是 G &#xff08; x ) G&#xff08;x) G&#xff08;x) 是已知的&#xff09;&#xff0…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)

目录 1.TCP的连接管理机制&#xff08;1&#xff09;三次握手①握手过程②对握手过程的理解 &#xff08;2&#xff09;四次挥手&#xff08;3&#xff09;握手和挥手的触发&#xff08;4&#xff09;状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

MMaDA: Multimodal Large Diffusion Language Models

CODE &#xff1a; https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA&#xff0c;它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构&#xf…...

【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表

1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

【AI学习】三、AI算法中的向量

在人工智能&#xff08;AI&#xff09;算法中&#xff0c;向量&#xff08;Vector&#xff09;是一种将现实世界中的数据&#xff08;如图像、文本、音频等&#xff09;转化为计算机可处理的数值型特征表示的工具。它是连接人类认知&#xff08;如语义、视觉特征&#xff09;与…...

Java入门学习详细版(一)

大家好&#xff0c;Java 学习是一个系统学习的过程&#xff0c;核心原则就是“理论 实践 坚持”&#xff0c;并且需循序渐进&#xff0c;不可过于着急&#xff0c;本篇文章推出的这份详细入门学习资料将带大家从零基础开始&#xff0c;逐步掌握 Java 的核心概念和编程技能。 …...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

重启Eureka集群中的节点,对已经注册的服务有什么影响

先看答案&#xff0c;如果正确地操作&#xff0c;重启Eureka集群中的节点&#xff0c;对已经注册的服务影响非常小&#xff0c;甚至可以做到无感知。 但如果操作不当&#xff0c;可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...

Android第十三次面试总结(四大 组件基础)

Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成&#xff0c;用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机&#xff1a; ​onCreate()​​ ​调用时机​&#xff1a;Activity 首次创建时调用。​…...

技术栈RabbitMq的介绍和使用

目录 1. 什么是消息队列&#xff1f;2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...