Flutter的状态管理之Provider

news2024/11/27 5:24:40

Provider简介

Flutter Provider是Flutter中一个非常流行的状态管理库,它可以帮助开发者更加方便地管理应用程序中的状态。Provider提供了一种简单的方式来共享和管理应用程序中的数据,并且可以根据数据的变化来自动更新UI界面。

Provider的核心思想是将数据作为一个全局的单例对象,然后通过InheritedWidget的上下文来共享这个对象。当数据发生变化时,Provider会通知依赖它的UI组件进行更新。这种设计模式非常适合Flutter应用程序中的状态管理,因为它可以避免使用全局变量和回调函数来管理状态。

使用

在Provider中,我们需要定义一个数据模型类,这个类通常包含了我们需要共享的一些数据和状态。例如,一个计数器应用程序的数据模型类可能如下所示:

class CounterModel extends ChangeNotifier {
  int _count = 0;
  int get count => _count;
  void increment() {
    _count++;
    notifyListeners();
  }
}

在这个数据模型类中,我们定义了一个名为CounterModel的类,并继承了ChangeNotifier类,这个类是Provider库中提供的一个基类,它实现了通知UI组件更新的功能。我们还定义了一个私有的计数器变量_count和一个公有的计数器变量count,以及一个increment方法用于增加计数器的值,并调用notifyListeners方法来通知UI组件更新。

接下来,在我们的应用程序中,我们需要使用Provider来共享这个CounterModel对象。这可以通过Provider的of方法来实现,例如:

class MyApp extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (context) => CounterModel(),
      child: MaterialApp(
        home: CounterPage(),
      ),
    );
  }
}

class CounterPage extends StatelessWidget {
  
  Widget build(BuildContext context) {
    final counter = Provider.of<CounterModel>(context);
    return Scaffold(
      appBar: AppBar(title: Text('Counter Example')),
      body: Center(
        child: Text('${counter.count}'),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => counter.increment(),
        child: Icon(Icons.add),
      ),
    );
  }
}

在这个例子中,我们在MyApp类中创建了一个ChangeNotifierProvider对象,并将CounterModel对象作为create方法的返回值传递进去。然后,在CounterPage类中,我们使用Provider.of方法获取CounterModel对象,并将其传递给UI组件。当用户点击浮动按钮时,我们调用CounterModel的increment方法来增加计数器的值,并且由于我们已经使用了Provider来共享数据,所以UI组件会自动更新显示计数器的值。

Flutter Provider是一个非常方便和强大的状态管理库,它可以帮助我们更加方便地管理应用程序中的状态,并且可以避免一些常见的状态管理问题。

Provider(create: (_) => MyModel(), child: ...) 是Provider库中的一个构造函数,用于创建一个共享MyModel对象的Provider。这个构造函数有两个参数:

  1. create: 一个回调函数,用于创建MyModel对象。这个回调函数的参数是BuildContext对象,但在这个例子中,我们没有使用这个参数,所以使用了一个下划线(_)来表示它是一个未使用的参数。在这个回调函数中,我们可以创建并返回MyModel对象。

  2. child: 一个Widget,它是Provider的子节点。在这个例子中,我们没有提供具体的Widget,所以使用了省略号(…)表示这是需要替换成其他的Widget的占位符。

当我们使用Provider(create: (_) => MyModel(), child: ...) 构造函数创建一个Provider时,Provider库会自动将MyModel对象共享给所有使用Provider.of(context)方法的Widget。这意味着,当我们在应用程序中的任何地方调用Provider.of(context)时,我们都可以获取到同一个MyModel对象的实例。如果我们在MyModel对象中修改了数据,这些变化将自动通知依赖它的Widget进行更新。

注意

需要注意的是,Provider的作用域是有限的。也就是说,当我们在Provider的子树之外的Widget中调用Provider.of(context)时,它将会抛出一个异常。因此,在使用Provider时,我们需要将它放在需要共享数据的Widget的父节点上,以确保Provider的作用域覆盖所有需要使用共享数据的Widget。

总结来说,Provider(create: (_) => MyModel(), child: ...) 是一个用于创建共享MyModel对象的Provider的构造函数,它可以帮助我们更加方便地管理应用程序中的状态,并且可以根据数据的变化来自动更新UI界面。

踩坑

遇到的错误

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';


class CounterModel extends ChangeNotifier {
  int _count = 0;
  int get count => _count;
  void increment() {
    _count++;
    notifyListeners();
  }
}

class TestPage extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Counter Page'),
      ),
      body: ChangeNotifierProvider(
        create: (context) => CounterModel(),
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(
                'You have pushed the button this many times:',
              ),
              Consumer<CounterModel>(
                builder: (context, counter, child) => Text(
                  '${counter.count}',
                  style: Theme.of(context).textTheme.headlineMedium,
                ),
              ),
            ],
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          Provider.of<CounterModel>(context, listen: false).increment();
        },
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

以上源码报错
Error: Could not find the correct Provider above this TestPage Widget

image.png

原因分析

这个错误通常是由于没有正确的将 ChangeNotifierProvider 注册在 TestPage 的父级 widget 中引起的。在这种情况下,您需要确保 TestPage 的父级 widget 包括 ChangeNotifierProvider。

解决方法

一种解决方法是将 ChangeNotifierProvider 注册在 MaterialApp 的顶级 widget 中,如下所示:

class MyApp extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (context) => CounterModel(),
      child: MaterialApp(
        title: 'My App',
        home: TestPage(),
      ),
    );
  }
}

在这个例子中,ChangeNotifierProvider 注册在 MyApp widget 中,并将 CounterModel 提供给整个应用程序。这样,当 TestPage 被创建时,它将能够访问 CounterModel 实例。

如果您不想在 MyApp 中注册 ChangeNotifierProvider,则可以将其注册在 TestPage 的父级 widget 中。例如,您可以创建一个新的 widget 并将其包装在 ChangeNotifierProvider 中,然后将该 widget 用作 TestPage 的父级 widget,如下所示:

class MyHomePage extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (context) => CounterModel(),
      child: TestPage(),
    );
  }
}

class TestPage extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Counter Page'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              'You have pushed the button this many times:',
            ),
            Consumer<CounterModel>(
              builder: (context, counter, child) => Text(
                '${counter.count}',
                style: Theme.of(context).textTheme.headlineMedium,
              ),
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          Provider.of<CounterModel>(context, listen: false).increment();
        },
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

在这个例子中,我们创建了一个新的 widget MyHomePage,并将 ChangeNotifierProvider 包装在其中。然后,我们将 TestPage 用作 MyHomePage 的子 widget,并在 TestPage 中访问 CounterModel。这样,当 TestPage 被创建时,它将能够访问 CounterModel 实例。

修改后的结果

按这个思路修改后,按+按钮,没有报错了,计数能正常刷新了。
image.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/620942.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

网络协议——什么是RIP协议?工作原理是什么?

作者&#xff1a;Insist-- 个人主页&#xff1a;insist--个人主页 作者会持续更新网络知识和python基础知识&#xff0c;期待你的关注 目录 一、什么是RIP协议&#xff1f; 二、为什么要使用RIP&#xff1f; 三、RIP用在哪里&#xff1f; 四、RIP协议的工作原理 五、总结 …

Redis安装布隆过滤器

目录 1 什么是布隆过滤器1.1 布隆过滤器的原理1.2 布隆过滤器缺点 2 插件形式安装2.1 下载布隆过滤器插件 3 docker方式单机安装4 Redis集群部署安装4.1 创建目录4.2 redis配置文件4.3 配置docker-compose.yml文件4.4 启动布隆过滤器集群4.5 配置集群4.6 布隆过滤器常用命令4.7…

如何将simulink中的元件(光伏板)导入到plecs中使用

simulink中有一些元件在plecs中是没有的&#xff0c;如果想要直接使用simulink的库&#xff0c;可以这样操作&#xff1a; 1 新建mdl文件&#xff08;simulink的文件类型&#xff09;&#xff0c;并在该文件中搭建好想要的模型、元件&#xff08;只放想要导出的元件就可以了&…

商城检索 DSL

模糊匹配过滤&#xff08;按照属性、分类、品牌、价格区间、库存&#xff09;排序分页高亮聚合分析 一. 搜索关键字 检索字段&#xff1a;商品sku标题 “skuTitle” : “华为 HUAWEI Mate 30 Pro 亮黑色 8GB256GB麒麟990旗舰芯片OLED环幕屏双4000万徕卡电影四摄4G全网通手机”…

基于Java+SpringBoot+Vue前后端分离考试学习一体机设计与实现(视频讲解)

博主介绍&#xff1a;✌全网粉丝3W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

docker-compose单机容器集群编排

docker-compose dockerfile模板文件可以定义一个独立的应用容器&#xff0c;如果需要多个容器就需要服务编排。服务编排有很多技术方案 docker-compose开源的项目实现对容器集群的快速编排 docker-compose将所管理的容器分为三层&#xff0c;分别为工程&#xff0c;服务&#…

Jenkins+RF持续集成测试(三) 生成测试报告并发给指定人

在上一篇《定时更新SVN完成构建》中讲了定时从SVN拉取最新的测试脚本&#xff0c;并自动构建的过程。这篇我将介绍怎么配置测试robot报告&#xff0c;并发送给指定人群。 1、要发给指定人&#xff0c;首先需要在job配置&#xff0c;构建后操作中增加“Editable Email Notificat…

day3 ARM寄存器组织

目录 寄存器 ARM寄存器 专用寄存器 CPSR寄存器 寄存器 概念&#xff1a;寄存器是处理器内部的存储器&#xff0c;没有地址&#xff1b; 作用&#xff1a;一般用于暂时存放参与运算的数据和运算结果&#xff1b; 分类&#xff1a;包括通用寄存器、专用寄存器、控制寄存器&…

腾讯云数据库2022下半年本地部署市场收入同比增速达110%,远超市场平均水平

6月7日&#xff0c;记者获悉&#xff0c;据全球领先的IT市场研究和咨询公司IDC发布的《2022年下半年中国关系型数据库软件市场跟踪报告》显示&#xff0c;在Top 5厂商中&#xff0c;腾讯云数据库整体收入同比增速、本地部署模式收入同比增速均位列第一。 具体来看&#xff0c;…

ChatPPT一键制作PPT,效果拉满~

&#x1f4a7; C h a t P P T 一 键 制 作 P P T &#xff0c; 效 果 拉 满 &#xff01; \color{#FF1493}{ChatPPT一键制作PPT&#xff0c;效果拉满&#xff01;} ChatPPT一键制作PPT&#xff0c;效果拉满&#xff01;&#x1f4a7; &#x1f337; 仰望天空&#xf…

网络安全面试题集及答案整理汇总(2023最新版详细)

前言 随着国家政策的扶持&#xff0c;网络安全行业也越来越为大众所熟知&#xff0c;想要进入到网络安全行业的人也越来越多。 为了拿到心仪的Offer之外&#xff0c;除了学好网络安全知识以外&#xff0c;还要应对好企业的面试。 作为一个安全老鸟&#xff0c;工作这么多年&…

如何安装intellij IDEA

想要自学编程&#xff0c;又不知道从那开始&#xff0c;百度找起来比较费劲&#xff0c;现在有个比较便捷的途径&#xff0c;就是直接问chatgpt。 在询问chatgpt后&#xff0c;得知目前比较流行的开发工具是intellij IDEA&#xff0c;然后问了chatgpt怎么下载这个工具&#xf…

当Python程序员好不好?我用自己的亲身经历告诉大家

最近有很多人问我是否考虑转行成为Python程序员&#xff0c;包括一些非计算机专业的学生和工作了几年的人。对于这个问题&#xff0c;我不太好给出建议&#xff0c;只能以我的个人经历来谈一下。我个人认为&#xff0c;我处于整个程序员群体的中位水平线上&#xff0c;因此大家…

开源飞行控制库QGroundControl认识

QGroundControl provides full flight control and vehicle setup for PX4 or ArduPilot powered vehicles. It provides easy and straightforward usage for beginners, while still delivering high end feature support for experienced users. QGroundControl为PX4或Ard…

分布式事务解决方案详解

分布式事务 分布式协议 XA规范 XA&#xff08;eXtended Architecture&#xff09;标准是X/Open 组织针对分布式事务&#xff08;DTP&#xff09;处理的规范&#xff0c;它描述了全局事务管理器和本地资源管理器之间的接口&#xff0c;允许多个资源在同一分布式事务中访问。DT…

Linux——内存和DMA(二)

目录 六、动态内存实例 七、 I/0内存 八、DMA原理及映射 8.1 DMA 工作原理 8.2 DMA映射 1.一致性DMA映射 2. 流式DMA映射 3&#xff0c;分散/聚集映射 4.DMA池 5&#xff0c;回弹缓冲区 九、 DMA统一编程接口 十、习题 书接上回&#xff1a; http://t.csdn.cn/n35…

Redis(二)——Redis持久化与主从架构详解

Redis持久化与主从架构详解 Redis的持久化RDB快照&#xff08;snapshot&#xff09;&#xff08;redis默认持久化方式&#xff09;bgsave的写时复制(COW)机制save与bgsave对比 AOF&#xff08;append-only file&#xff09;配置 Redis 多久才将数据 fsync 到磁盘一次AOF重写 如…

网站创建百度百科词条的方法是什么?

百度百科是一个十分全面的在线百科全书&#xff0c;如果您是某个企业、品牌&#xff0c;或是某个行业或领域的专家&#xff0c;想要在百度百科上为自己的网站创造更多曝光率和权威性&#xff0c;那么在百度百科上创建词条就是一项非常有效的方法。这里需要注意的是创建网站类的…

一、OkHttp_网络请求流程

前言&#xff1a; 一直以来总想对android常用的某个第三方库深入研究一下&#xff0c;每次看完源码之后总是经常的忘记。 为了方便对三方库快速阅读&#xff0c;特此以写文章方式记述。 就从OKHttp开始吧。 再阅读源码之前&#xff0c;要明确 OKHttp是用来做什么的&#xff1f;…

交互原型图设计必备软件,这5款太赞了

如果你是UI/UX设计师&#xff0c;你肯定会在工作中涉及到交互原型图的设计。 在设计交互原型图时&#xff0c;我们通常需要找到一些适合自己的交互原型图设计软件来制作高质量的交互原型图。 与您分享5款易于使用的交互原型图设计软件 1.即时设计 即时设计是国内UI/UX设计师…