[Flutter]使用Provider进行状态管理

一、使用Provider进行状态管理的基本用法

Provider是Flutter中一个非常流行的状态管理工具,它可以帮助开发者更有效地管理Widget树中的数据。Provider的核心思想是将数据模型放置在Widget树中可以被多个子Widget访问的地方,而不必通过构造函数手动传递。

1.添加provider依赖

dependencies:
  flutter:
    sdk: flutter
  provider: ^6.0.0  

2.创建一个数据模型

import 'package:flutter/material.dart';

class CounterModel with ChangeNotifier {
  int _count = 0;

  int get count => _count;

  void increment() {
    _count++;
    notifyListeners(); // 通知监听者数据改变
  }
}

3.在应用中提供模型

在你的应用中,你需要在一个合适的位置(如MaterialApp的上方)使用ChangeNotifierProvider来创建并提供CounterModel的实例。

import 'package:provider/provider.dart';

void main() {
  runApp(
    // 注意:ChangeNotifierProvider要包装在MaterialApp之外
    ChangeNotifierProvider(
      create: (context) => CounterModel(),
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomeScreen(),
    );
  }
}

4.使用ConsumerProvider.of读取和显示数据

在你的HomeScreen中,你可以使用ConsumerProvider.of来读取CounterModel的数据,并构建UI。

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Provider Example'),
      ),
      body: Center(
        // 使用Consumer来监听CounterModel
        child: Consumer<CounterModel>(
          builder: (context, counter, child) => Text('${counter.count}'),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // 不需要监听改变时,可以直接使用Provider.of来访问模型
          Provider.of<CounterModel>(context, listen: false).increment();
        },
        child: Icon(Icons.add),
      ),
    );
  }
}

当你点击浮动按钮时,increment方法会被调用,CounterModel中的计数器会增加,并通过notifyListeners通知Consumer重新构建,这样UI上显示的数字就会更新。

注意:

  • 使用Provider.of(context)时,如果你不需要监听变化,可以设置listen: false,这样可以提高性能。
  • 当模型更新时,只有通过Consumer或者Provider.of(context)(并且listen设置为true)获取模型的Widget才会重新构建。

二、管理多个不同的状态

如果你有多个不同的状态需要管理,你通常会为每种状态创建不同的模型。每个模型专注于管理一组相关的状态数据和行为。这样可以帮助你保持代码的清晰和分离关注点,使得每个模型都保持简单和专注。

但是,如果你的状态数据非常紧密相关,并且它们通常一起改变,那么将它们放在同一个模型中也是有意义的。

1.创建多个模型

计数器模型
class CounterModel with ChangeNotifier {
  int _count = 0;

  int get count => _count;

  void increment() {
    _count++;
    notifyListeners();
  }
}
主题色彩模型
class ThemeModel with ChangeNotifier {
  ThemeData _themeData = ThemeData.light();

  ThemeData get themeData => _themeData;

  void toggleTheme() {
    _themeData = _themeData == ThemeData.light() ? ThemeData.dark() : ThemeData.light();
    notifyListeners();
  }
}

2.同时管理多个状态

在你的应用中,你可以使用MultiProvider来同时提供多个模型:

void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (context) => CounterModel()),
        ChangeNotifierProvider(create: (context) => ThemeModel()),
      ],
      child: MyApp(),
    ),
  );
}

你现在可以根据ThemeModel提供的主题数据来构建你的应用程序:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Consumer<ThemeModel>(
      builder: (context, themeModel, child) {
        return MaterialApp(
          theme: themeModel.themeData,
          home: HomeScreen(),
        );
      },
    );
  }
}

这样,你就可以在HomeScreen或者其他任何Widget中分别访问和操作CounterModelThemeModel了。通过这种方式,你可以将应用的不同部分的状态管理分离开来,从而使你的代码更加模块化和可维护。

三、异步获取状态

有时,我们不想在模型内部中直接管理状态,而是每次修改SharedPreferences中的缓存数据,以及直接从SharedPreferences获取状态。更进一步,比如异步从网络获取状态,也是类似的。

比如,我们要管理一个订阅状态。

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

class SubscriptionStatusModel extends ChangeNotifier {

  // 订阅状态的异步读取方法
  Future<bool> get isSubscribed async {
    final prefs = await SharedPreferences.getInstance();
    return prefs.getBool('isSubscribeValid') ?? false;
  }

  // 更新SharedPreferences中的订阅状态
  Future<void> updateSubscriptionStatus(bool newStatus) async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setBool('isSubscribeValid', newStatus);
    notifyListeners();  // 通知监听器可能有变化
  }

}

在上面的代码中,isSubscribed 现在是一个异步 getter,每次调用时都会从 SharedPreferences 中读取订阅状态。updateSubscriptionStatus 方法现在会将新状态写入 SharedPreferences 并通知监听器。

这样修改后,你就需要在UI中相应地处理Future。例如,如果你在一个widget中使用这个模型,你可能需要使用 FutureBuilder

FutureBuilder<bool>(
  future: provider.isSubscribed, // 假设` provider `是你的SubscriptionStatusModel实例
  builder: (context, snapshot) {
    if (snapshot.connectionState == ConnectionState.waiting) {
      // 等待数据时返回加载指示器
      return CircularProgressIndicator();
    } else if (snapshot.hasError) {
      // 处理错误情况
      return Text('Error: ${snapshot.error}');
    } else {
      // 使用订阅状态来构建widget
      bool isSubscribed = snapshot.data ?? false;
      return Text(isSubscribed ? 'Subscribed' : 'Not subscribed');
    }
  },
)

实际用例:

Stack(
  alignment: Alignment.center,
  children: [
    CustomScrollView(
       // ...
    ),
    Consumer<SubscriptionStatusModel>(builder: (context, provider, child) {
      return FutureBuilder<bool>(
        future: provider.isSubscribed,  
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            // 等待数据时返回加载指示器
            // return CircularProgressIndicator();
            return SizedBox.shrink();
          } else if (snapshot.hasError) {
            // 处理错误情况
            // return Text('Error: ${snapshot.error}');
            return SizedBox.shrink();
          } else {
            // 使用订阅状态来构建widget
            bool isSubscribed = snapshot.data ?? false;
            return Visibility(
              visible: !isSubscribed,
              child: Positioned(
                left: 0,
                right: 0,
                bottom: 16,
                child: _subscribeButton(),
              ),
            );
          }
        },
      );
    }),
  ],
),

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python办公自动化之PDF(二)

Python操作PDF二 1、PyMuPDF简介2、 1、PyMuPDF简介 PyMuPDF&#xff08;也称Fitz&#xff09;开源&#xff0c;提供了一整套用于处理PDF文件的综合工具。使用PyMuPDF&#xff0c;用户可以高效地执行打开PDF、提取文本、图像和表格、操作旋转和裁剪等页面属性、创建新PDF文档以…

Pytorch线性回归实现(原理)

设置梯度 直接在tensor中设置 requires_gradTrue&#xff0c;每次操作这个数的时候&#xff0c;就会保存每一步的数据。也就是保存了梯度相关的数据。 import torch x torch.ones(2, 2, requires_gradTrue) #初始化参数x并设置requires_gradTrue用来追踪其计算历史 print(x…

OpenHarmony教程指南—事件的订阅和发布

介绍 本示例主要展示了公共事件相关的功能&#xff0c;实现了一个检测用户部分行为的应用。具体而言实现了如下几点功能&#xff1a; 1.通过订阅系统公共事件&#xff0c;实现对用户操作行为&#xff08;亮灭屏、锁屏和解锁屏幕、断联网&#xff09;的监测&#xff1b; 2.通…

ELK介绍使用

文章目录 一、ELK介绍二、Elasticsearch1. ElasticSearch简介&#xff1a;2. Elasticsearch核心概念3. Elasticsearch安装4. Elasticsearch基本操作1. 字段类型介绍2. 索引3. 映射4. 文档 5. Elasticsearch 复杂查询 三、LogStash1. LogStash简介2. LogStash安装 四、kibana1. …

粉嘟嘟的免费wordpress模板

粉色好看的wordpress免费模板&#xff0c;用免费wordpress模板也可以搭建网站。 https://www.wpniu.com/themes/11.html

Android使用WebView打开内嵌H5网页

Android打开外部网页链接请参考上一篇文章 https://public.blog.csdn.net/article/details/136384559 继上篇&#xff0c;新建assets文章夹&#xff0c;将H5的网页资源放到此文件夹下 把H5的资源文件都拷进来 这个时候&#xff0c;将添加打开本地网页的代码&#xff1a; //打…

unicloud 集合 Collection 详解及其使用示例

Collection Collection是unicloud数据的指定表集合 获取集合Collection示例如下 const db uniCloud.database(); // 获取 user 集合的引用 const collection db.collection(user);集合 Collection 通过 db.collection(name) 可以获取指定集合的引用&#xff0c;在集合上可…

西部广播电视杂志社《西部广播电视》杂志社2024年第1期目录

聚焦&#xff1a;动漫创作中国故事的突破 从接受美学看奇幻电影如何讲好中国故事——以电影《封神第一部&#xff1a;朝歌风云》为例 郭海芃; 1-4 梦境构筑叙事隐含类型突破——以动画电影《深海》为例 李雯萱; 5-9 国产动画“全龄化”的创作突破——以《长安三万里…

leetcode 热题 100_除自身以外数组的乘积

题解一&#xff1a; 前缀 / 后缀数组&#xff1a;某元素除自身以外的乘积&#xff0c;也就是其全部前缀元素乘积 * 全部后缀元素乘积&#xff0c;因此我们可以构造前缀数组和后缀数组&#xff0c;分别存储前i个元素的成绩和后i个元素的乘积&#xff0c;再将i-1前缀乘积 * i1后缀…

系统提示mfc100u.dll丢失或错误的解决方法分享

mfc100u.dll是Microsoft Foundation Classes (MFC)库中的一个关键动态链接库文件。 mfc100u.dll文件是Microsoft Foundation Classes (MFC)库的一部分&#xff0c;这是一个为软件开发者提供的一系列类和功能&#xff0c;旨在简化Windows应用程序的开发过程。这个特定的文件包含…

Python基础三

一、模块&#xff08;model&#xff09; 1、定义 以.py 结尾的文件&#xff0c;包含了Python对象定义和Python语句 如下&#xff1a;包含了两个模块&#xff0c;分别为 main.py 和 model.py 2、特点 模块让你能够有逻辑地组织你的Python 代码段。把相关的代码分配到一个模块…

阿珊详解Vue路由的两种模式:hash模式与history模式

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

Hotchips2018年-英伟达V100展示肌肉(未来芯片论坛及资料下载)

HOTCHIPS是什么&#xff1f; HOTCHIPS是一个关于计算机体系结构和电子设计的会议&#xff0c;主要探讨芯片设计、存储器、能源效率、机器学习和人工智能等方面的发展。该会议每年都会召开一次&#xff0c;吸引着来自世界各地的专业人士和研究人员。 在HOTCHIPS 2018年会上&a…

MySQL安装与卸载

安装 1). 双击官方下来的安装包文件 2). 根据安装提示进行安装(全部默认就可以) 安装MySQL的相关组件&#xff0c;这个过程可能需要耗时几分钟&#xff0c;耐心等待。 输入MySQL中root用户的密码,一定记得记住该密码 配置 安装好MySQL之后&#xff0c;还需要配置环境变量&am…

C++泛型实现搜索二叉树

文章目录 二叉搜索树查找插入删除实现应用性能分析 二叉搜索树 二叉搜索树&#xff08;BST&#xff0c;Binary Search Tree&#xff09;又称为二叉排序树&#xff0c;空树也算 二叉搜索树有如下性质 若左子树不为空&#xff0c;则左子树上所有节点值小于根节点若右子树不为空…

Tonka Finance,BTCFi 浪潮的发动机

在 2023 年年初&#xff0c;Ordinals 技术方案为比特币 Layer1 带来了一种全新的资产发行方式&#xff0c;此后一场以比特币生态为主战场的新一轮资金、注意力价值争夺战打响&#xff0c;并且越来越多的加密原教旨主义者、密码极客们加入这场战争中。我们看到&#xff0c;铭文市…

类和对象(1)(至尊详解版)

相信对于大家而言&#xff0c;对于类和对象都会是一头雾水吧&#xff01;什么是类&#xff1f;或者你有对象吗&#xff1f;那么本期的内容呢&#xff1f;就由我来为大家再次增加对于它们的理解&#xff0c;由于水平上的原因&#xff0c;可能会存在不当之处&#xff0c;敬请读者…

局域网管理工具

每个组织的业务运营方法都是独一无二的&#xff0c;其网络基础设施也是如此&#xff0c;由于随着超融合基础设施等新计算技术的发展&#xff0c;局域网变得越来越复杂&#xff0c;因此局域网管理也应该如此&#xff0c;组织需要量身定制的局域网管理解决方案&#xff0c;这些解…

【FPGA】DDR3学习笔记(一)丨SDRAM原理详解

本篇文章包含的内容 一、DDR3简介1.1 DDR3 SDRAM概述1.2 SDRAM的基础结构 二、 SDRAM操作时序2.1 SDRAM操作指令2.2 模式寄存器&#xff08;LOAD MODE REGISTER&#xff09;2.3 SDRAM操作时序示例2.3.1 SDRAM初始化时序2.3.2 突发读时序2.3.3 随机读时序2.3.4 突发写时序2.3.5 …

计算机这几个炮灰专业,选错毕业直接去搬砖

计算机五大专业&#xff0c;选错毕业后直接去搬砖。 在所有的计算机类专业中&#xff0c;计算机科学与技术这个专业既要学硬件&#xff0c;也要学软件&#xff0c;既要学理论&#xff0c;也要学技术。课程既有数理类&#xff0c;也有电器类&#xff0c;还有计算机类&#xff0…
最新文章