【Flutter】状态管理:Provider状态管理
在 Flutter 开发中,状态管理是一个至关重要的部分。随着应用的规模和复杂性增加,简单的局部状态管理(如 setState() 和 InheritedWidget)可能变得难以维护和扩展。Provider 是一种推荐的、广泛使用的 Flutter 状态管理工具,它能够帮助我们更轻松地管理应用中复杂的全局状态,并且具有高效、易于使用的特性。
本教程将详细介绍如何使用 Provider 来管理 Flutter 应用中的状态,内容包括 ChangeNotifier 和 Consumer 的基本用法,以及如何使用 MultiProvider 和 ProxyProvider 来管理复杂的状态依赖关系。
什么是 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 安装依赖。
ChangeNotifier 与 ChangeNotifierProvider
ChangeNotifier 是 Provider 中最常用的状态管理工具。它提供了一种简单的机制来监听状态的变化,并通知所有依赖该状态的组件进行重新构建。
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),),);}
}
代码详解
-
Counter类:它继承了ChangeNotifier,内部定义了一个私有变量_count和对应的get方法count,同时通过increment()方法改变状态并调用notifyListeners()通知所有依赖该状态的组件。 -
ChangeNotifierProvider:它包装了MyApp并提供了Counter的实例。create方法用于在组件树的最顶层创建并提供一个Counter实例。 -
Consumer:它用于订阅Counter的状态变化。当状态变化时,Consumer会自动重建其子组件并更新界面。builder回调提供了当前的状态(即Counter实例)。 -
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),),);}
}
代码详解
-
UserInfo和Cart类:分别表示用户信息和购物车的状态,它们都继承自ChangeNotifier。 -
MultiProvider:用于一次性提供多个ChangeNotifier。通过providers参数,我们可以同时提供UserInfo和Cart的状态。 -
Consumer:两个Consumer分别监听UserInfo和Cart的状态变化,并更新界面。
通过 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}'),),);}
}
代码详解
-
UserInfo类:管理用户信息。 -
Order类:订单类,它依赖于UserInfo,即每个订单都与用户关联。 -
ProxyProvider:用于处理Order依赖UserInfo的场景。update方法会在UserInfo变化时重新创建Order实例。
总结
通过学习 Provider,你已经掌握了 Flutter 中一种强大的全局状态管理工具。Provider 可以帮助你轻松实现跨组件状态共享、复杂状态依赖管理,并且保持代码的简洁性和可维护性。
相关文章:
【Flutter】状态管理:Provider状态管理
在 Flutter 开发中,状态管理是一个至关重要的部分。随着应用的规模和复杂性增加,简单的局部状态管理(如 setState() 和 InheritedWidget)可能变得难以维护和扩展。Provider 是一种推荐的、广泛使用的 Flutter 状态管理工具&#x…...
来个Oracle一键检查
启停、切换、升级、网络改造等场景下,需要对数据库有些基本检查操作,确认当前是否运行正常,主打一个简单和一键搞定。 #!/bin/bash## 实例个数 告警日志 实例状态 会话 活动会话 锁 集群状态 服务状态 磁盘空间 侦听日志 ## linux vmstat 2 …...
C语言中的分支与循环(中 1)
关系操作符 C语言用于比较的表达式,称为"关系表达式",里面使用的运算符称为关系运算符,关系运算符主要有以下6类。 > 大于运算符< 小于运算符>大于等于运算符< 小于等于运算符 相等运算符! 不相等运算符 下面是例子:…...
Git_GitLab
Git_GitLab 安装 服务器准备 安装包准备 编写安装脚本 初始化 GitLab 服务 启动 GitLab 服务 浏览器访问 GitLab GitLab 创建远程库 IDEA 集成 GitLab 安装 GitLab 插件 设置 GitLab 插件 安装 服务器准备 准备一个系统为 CentOS7 以上版本的服务器,使…...
如何自定义一个自己的 Spring Boot Starter 组件(从入门到实践)
文章目录 一、什么是 Spring Boot Starter?二、为什么要自定义 Starter?三、自定义 Starter 的基本步骤1. 创建 Maven 项目2. 配置 pom.xml3. 创建自动配置类4. 创建业务逻辑类5. 创建 spring.factories 四、使用自定义 Starter五、总结推荐阅读文章 在使…...
CSS伪元素以及伪类和CSS特性
伪元素:可以理解为假标签。 有2个伪元素 (1)::before (2)::after ::before <!DOCTYPE html> <html> <head><title></title><style type"text/css">body::before{con…...
【论文笔记】Instantaneous Perception of Moving Objects in 3D
原文链接:https://arxiv.org/abs/2405.02781 简介:本文主张自动驾驶中细微运动的瞬时检测和量化与一般的大型运动同等重要。具体来说,由于激光雷达点云缺乏帧间对应关系,静态物体可能看起来在运动(称为游泳效应&#x…...
Segugio:一款针对恶意软件的进程执行跟踪与安全分析工具
关于Segugio Segugio是一款功能强大的恶意软件安全分析工具,该工具允许我们轻松分析恶意软件执行的关键步骤,并对其进行跟踪分析和安全审计。 Segugio允许执行和跟踪恶意软件感染过程中的关键步骤,其中包括从点击第一阶段到提取恶意软件的最…...
互联网系统的微观与宏观架构
互联网系统的架构设计,通常会根据项目的体量、业务场景以及技术需求被划分为微观架构(Micro-Architecture)和宏观架构(Macro-Architecture)。这两者的概念与职责既独立又相互关联。本文将通过一些系统案例,…...
数据库、数据仓库、数据湖和数据中台有什么区别
很多企业在面对数据存储和管理时不知道如何选择合适的方式,数据库、数据仓库、数据湖和数据中台,这些方式都是什么?有什么样的区别?企业根据其业务类型该选择哪一种?本文就针对这些问题,来探讨下这些方式都…...
vscode配色主题与图标库推荐
vscode配色主题推荐:Andromedavsocde图标库: vscode-icons Andromeda Dark theme with a taste of the universe 仙女座:一套宇宙深空体验的哑暗色主题; 高对比度,色彩饱和; Easy Installation Open the extensions sidebar on Visual Studio CodeSear…...
深度学习模型入门教程:从基础到应用
深度学习模型入门教程:从基础到应用 前言 在人工智能的浪潮中,深度学习作为一种强大的技术,正在各行各业中发挥着越来越重要的作用。从图像识别到自然语言处理,深度学习正在改变我们的生活和工作方式。本文将带您深入了解深度学…...
数据结构 软考
算法具有5个特性 可行性,有限性,确定性,输入, 输出 图: 有向图 Kruskal(克鲁斯卡尔)算法 和 prim(普鲁姆)算法 都是贪心算法 是一种用来在加权连通图中寻找最小生成树的算法,其操作对象是边. 找最小的不形成环 1.哈夫曼树(也叫最优树)…...
colcon构建ros2功能包时,出现exited with code 2报错的解决方案(bug)
背景: 在学习ros2时,跟着别人的示例进行构建,手敲的代码难免有一些语法错误。 问题: 在colcon构建时,并不会直接输出语法报错。而是出现exited with code 2错误,并提示未能生成功能包,就算加入…...
【大模型LLM面试合集】大语言模型架构_位置编码
位置编码 1.位置编码 不同于RNN、CNN等模型,对于Transformer模型来说,位置编码的加入是必不可少的,因为纯粹的Attention模块是无法捕捉输入顺序的,即无法区分不同位置的Token。为此我们大体有两个选择: 想办法将位置…...
FLINK 分流
在Apache Flink中,分流(Stream Splitting)是指将一条数据流拆分成完全独立的两条或多条流的过程。这通常基于一定的筛选条件,将符合条件的数据拣选出来并放入对应的流中。以下是关于Flink分流的详细解释: 一、分流方式…...
从零开始:构建一个高效的开源管理系统——使用 React 和 Ruoyi-Vue-Plus 的实战指南
✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…...
windows下pycharm社区版2024下载与安装(包含新建第一个工程)
windows下pycharm社区版2024下载与安装 下载pycharm pycharm官网 安装pycharm 1.进入官网 pycharm官网 下载 点击Download–>右侧Other versions 下载对应的社区版(如下图):下载网址 2.点击运行下载好的安装包 点击下一步 3.更改pychar…...
重构案例:将纯HTML/JS项目迁移到Webpack
我们已经了解了许多关于 Webpack 的知识,但要完全熟练掌握它并非易事。一个很好的学习方法是通过实际项目练习。当我们对 Webpack 的配置有了足够的理解后,就可以尝试重构一些项目。本次我选择了一个纯HTML/JS的PC项目进行重构,项目位于 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…...
练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...
关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...
学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...
比较数据迁移后MySQL数据库和OceanBase数据仓库中的表
设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...
PostgreSQL——环境搭建
一、Linux # 安装 PostgreSQL 15 仓库 sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{rhel})-x86_64/pgdg-redhat-repo-latest.noarch.rpm# 安装之前先确认是否已经存在PostgreSQL rpm -qa | grep postgres# 如果存在࿰…...
2025年- H71-Lc179--39.组合总和(回溯,组合)--Java版
1.题目描述 2.思路 当前的元素可以重复使用。 (1)确定回溯算法函数的参数和返回值(一般是void类型) (2)因为是用递归实现的,所以我们要确定终止条件 (3)单层搜索逻辑 二…...
