Flutter 状态管理的实现

一、什么是状态管理

大到整个app的状态,用户使用app是登录状态,还是游客状态;小到一个按钮的状态,按钮是点击选中状态还是未点击状态等等,这些都是状态管理。

二、命令式编程和声明式编程状态管理的区别

iOS是如何管理状态的,一般都是获取这个控件然后设置你想要的状态 当你的 Flutter 应用的状态发生改变时(例如,用户在设置界面中点击了一个开关选项)你改变了状态,这将会触发用户界面的重绘。去改变用户界面本身是没有必要的(例如 widget.setText )—你改变了状态,那么用户界面将重新构建。

三、状态管理中的声明式编程思维

Flutter 应用是 声明式 的,这也就意味着 Flutter 构建的用户界面就是应用的当前状态。

一旦你的界面状态发生改变,就会触发界面的重新绘制,绘制出你想要的界面,而不是像iOS的OC语言那样去获取需要改变状态的控件,然后修改它

四、短时 (ephemeral) 和应用 (app) 状态的区别

Flutter中的状态管理又分为短时状态和应用状态。

短时状态,就是在单个页面需要保持的状态,比如页面数据加载到了第几页,关注按钮是已关注还是未关注等,都是在单个页面需要保持的状态。widget树中其他部分不需要访问这种状态。不需要去序列化这种状态,这种状态也不会以复杂的方式改变。换句话说,不需要使用状态管理架构(例如 ScopedModel, Redux)去管理这种状态。你需要用的只是一个 StatefulWidget。

在下方你可以看到一个底部导航栏中当前被选中的项目是如何被被保存在 _MyHomepageState 类的 _index 变量中。在这个例子中,_index 是一个短时状态。

class MyHomepage extends StatefulWidget {
 @override
 _MyHomepageState createState() => _MyHomepageState();
}

class _MyHomepageState extends State<MyHomepage> {
 int _index = 0;

 @override
 Widget build(BuildContext context) {
  return BottomNavigationBar(
   currentIndex: _index,
   onTap: (newIndex) {
    setState(() {
     _index = newIndex;
    });
   },
   // ... items ...
  );
 }
}

在这里,使用 setState() 和一个变量就能达到管理状态的目的。你的 app 中的其他部分不需要访问 _index。这个变量只会在 MyHomepage widget 中改变。而且,如果用户关闭并重启这个 app,_index会被重置而不会继续保持原来的状态。

应用状态,如果你想在你的应用中的多个部分之间共享一个非短时的状态,并且在用户会话期间保留这个状态,我们称之为应用状态(有时也称共享状态)。 应用状态的一些例子:

1、用户选项

2、登录信息

3、一个社交应用中的通知

4、一个电商应用中的购物车

5、一个新闻应用中的文章已读/未读状态

五、共享状态管理

在 Flutter 中,一般是将存储状态的对象置于 widget 树中对应 widget 的上层,当它发生改变的时候,它对应的widget会从上层开始重构。因为这个机制,所以 widget 无需考虑生命周期的问题—它只需要针对 上层存储数据的对象 声明所需显示内容即可。当内容发生改变的时候,旧的 widget 就会消失,完全被新的 widget 替代。 Flutter原生提供了两个方法来管理共享状态:

5.1 --InheritedWidget

class ADCounterWidget extends InheritedWidget {
 // 1. 共享的数据
 final int counter;

 // 2. 定义构造方法
 ADCounterWidget({this.counter, Widget child}): super(child: child);

 // 3. 找到当前Widget树中最近的InheritedWidget
 static ADCounterWidget of(BuildContext context) {
  // 沿着Element树, 去找到最近的ADCounterElement, 从Element中取出Widget对象
  return context.dependOnInheritedWidgetOfExactType();
 }

 // 4. 要不要回调State中的didChangeDependencies方法
 @override
 bool updateShouldNotify(ADCounterWidget oldWidget) {
  return oldWidget.counter != counter;
 }
}

上面定义了一个of方法,该方法通过context开始去查找父级的HYDataWidget

updateShouldNotify方法是对比新旧HYDataWidget,是否需要对更新相关依赖的Widget

class HYHomePage extends StatefulWidget {
 @override
 _HYHomePageState createState() => _HYHomePageState();
}

class _HYHomePageState extends State<HYHomePage> {
 int data = 100;

 @override
 Widget build(BuildContext context) {
  return Scaffold(
   appBar: AppBar(
    title: Text("InheritedWidget"),
   ),
   body: HYDataWidget(
    counter: data,
    child: Center(
     child: Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
       HYShowData()
      ],
     ),
    ),
   ),
   floatingActionButton: FloatingActionButton(
    child: Icon(Icons.add),
    onPressed: () {
     setState(() {
      data++;
     });
    },
   ),
  );
 }
}

创建HYDataWidget,并且传入数据(这里点击按钮会修改数据,并且出发重新build)

5.2 --Provider

Provider库有三个主要用到的类:

  • ChangeNotifier:真正数据(状态)存放的地方
  • ChangeNotifierProvider:Widget树中提供数据(状态)的地方,会在其中创建对应的ChangeNotifier
  • Consumer:Widget树中需要使用数据(状态)的地方

第一步 在程序的最顶层创建自己的ChangeNotifier

  • 将ChangeNotifierProvider放到了顶层,这样方便在整个应用的任何地方可以使用CounterProvider
  • 在ChangeNotifier中创建一个私有的_counter,并且提供了getter和setter
  • 在setter中我们监听到_counter的改变,就调用notifyListeners方法,通知所有的Consumer进行更新
void main() {
 runApp(ChangeNotifierProvider(
  create: (context) => CounterProvider(),
  child: MyApp(),
 ));
}

class CounterProvider extends ChangeNotifier {
 int _counter = 100;
 intget counter {
  return _counter;
 }
 set counter(int value) {
  _counter = value;
  notifyListeners();
 }
}

第二步 在首页中使用Consumer引入和修改状态

  • 在body中使用Consumer,Consumer需要传入一个builder回调函数,当数据发生变化时,就会通知依赖数据的Consumer重新调用builder方法来构建
  • 在floatingActionButton中使用Consumer,当点击按钮时,修改CounterNotifier中的counter数据
class HYHomePage extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
  return Scaffold(
   appBar: AppBar(
    title: Text("列表测试"),
   ),
   body: Center(
    child: Consumer<CounterProvider>(
     builder: (ctx, counterPro, child) {
      return Text("当前计数:${counterPro.counter}", style: TextStyle(fontSize: 20, color: Colors.red),);
     }
    ),
   ),
   floatingActionButton: Consumer<CounterProvider>(
    builder: (ctx, counterPro, child) {
     return FloatingActionButton(
      child: child,
      onPressed: () {
       counterPro.counter += 1;
      },
     );
    },
    child: Icon(Icons.add),
   ),
  );
 }
}

Consumer的builder方法有三个参数:

  • context,每个build方法都会有上下文,目的是知道当前树的位置
  • ChangeNotifier对应的实例,也是我们在builder函数中主要使用的对象
  • child,目的是进行优化,如果builder下面有一颗庞大的子树,当模型发生改变的时候,我们并不希望重新build这颗子树,那么就可以将这颗子树放到Consumer的child中,在这里直接引入即可(注意我案例中的Icon所放的位置)

第四步 创建一个新的页面,在新的页面中修改数据

class SecondPage extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
  return Scaffold(
   appBar: AppBar(
    title: Text("第二个页面"),
   ),
   floatingActionButton: Consumer<CounterProvider>(
    builder: (ctx, counterPro, child) {
     return FloatingActionButton(
      child: child,
      onPressed: () {
       counterPro.counter += 1;
      },
     );
    },
    child: Icon(Icons.add),
   ),
  );
 }
}

到此这篇关于Flutter 状态管理的实现的文章就介绍到这了,更多相关Flutter 状态管理内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Flutter部件内部状态管理小结之实现Vue的v-model功能

    Flutter部件内部状态管理 本文是 Flutter 部件内部状态管理的小结,从部件的基础开始,到部件的状态管理,并且在过程中实现一个类似 Vue 的 v-model 的功能. widget 基础 widget(部件) 如 React 里万物皆组件, Java 里万物皆对象, Flutter 里,能看到的一切都是 widget(部件),如按钮.文本框等等. Flutter 内部已经为我们做了一些基础的 widget ,例如: Text : 这个就是一个文本部件,里面用于放置文本 Row , C

  • Flutter 状态管理的实现

    一.什么是状态管理 大到整个app的状态,用户使用app是登录状态,还是游客状态:小到一个按钮的状态,按钮是点击选中状态还是未点击状态等等,这些都是状态管理. 二.命令式编程和声明式编程状态管理的区别 iOS是如何管理状态的,一般都是获取这个控件然后设置你想要的状态 当你的 Flutter 应用的状态发生改变时(例如,用户在设置界面中点击了一个开关选项)你改变了状态,这将会触发用户界面的重绘.去改变用户界面本身是没有必要的(例如 widget.setText )-你改变了状态,那么用户界面将重新

  • Flutter状态管理Bloc之定时器示例

    本文实例为大家分享了Flutter状态管理Bloc之定时器的具体代码,供大家参考,具体内容如下 1. 依赖 dependencies:   flutter_bloc: ^2.1.1   equatable: ^1.0.1   wave: ^0.0.8 2. Ticker Ticker 用于产生定时器的数据流. /// 定时器数据源 class Ticker {      /// 定时器数据源   /// @param ticks 时间   Stream<int> tick({int ticks

  • Flutter状态管理Bloc之登录示例

    本文实例为大家分享了Flutter状态管理Bloc之登录的具体代码,供大家参考,具体内容如下 1. 依赖 dependencies:   flutter_bloc: ^2.1.1   equatable: ^1.0.1 2. UserRepository 用于管理用户数据 提供认证方法,删除Token,保存Token,是否包含Token四个方法. import 'package:flutter/material.dart';   /// 用户数据仓库 class UserRepository {

  • flutter状态管理Provider的使用学习

    目录 1. provider的使用 2. 控制Widget的刷新颗粒度 3. 小结 本文主要介绍flutter中状态管理组件provider,provider: ^6.0.3主要是用于我们系统InheritedWidge的封装,用于数据的传递和管理. 1. provider的使用 网上也有很多关于provider说明,也可以看下官方的provider的 README.这里我记录一下我自己学习.我们对于简单的数据共享可以设置参数,之后子页面进行数据方法回调,从而完成数据间的通信.但是比较麻烦,下面

  • Flutter状态管理Bloc使用示例详解

    目录 前言 两种使用模式 Cubit模式 最后 前言 目前Flutter三大主流状态管理框架分别是provider.flutter_bloc.getx,三大状态管理框架各有优劣,本篇文章将介绍其中的flutter_bloc框架的使用,他是bloc设计思想模式在flutter上的实现,bloc全程全称 business logic ,业务逻辑的意思,核心思想就是最大程度的将页面ui与数据逻辑的解耦,使我们的项目可读性.可维护性.健壮性增强. 两种使用模式 首先第一步引入插件: flutter_bl

  • Flutter状态管理Provider的使用示例详解

    目录 前言 计数器 全局状态 总结 前言 Provider是三大主流状态管理框架官方推荐使用的框架,它是基于官方数据共享组件InheritedWidget实现的,通过数据改变调用生命周期中的didChangeDependencies()方法,来实现状态的通知改变. InheritedWidget的使用可以参考我之前的这篇Flutter中几种数据传递的应用总结. 计数器 还是以计数器为例,这次通过Provider实现,provider相较于bloc并没有那么强制性分层,所以这里我们自己分为数据层(

  • 封装flutter状态管理工具示例详解

    目录 引言 RxBinder 代码实现 Demo 完美运行 引言 关于 Flutter 状态管理,公司项目使用的是Bloc方案.Bloc 其实本质上是 provider 的封装扩展库,整体通过 InheritedWidget .Notifier 外加 Stream中转实现状态变更通知. 关于 Bloc 实现原理,有兴趣的同学可以观看这篇文章 Bloc原理解析 RxBinder 撇开Bloc内部实现策略,小轰尝试基于数据驱动模型,自定义一套状态管理工具.构思如下: 主要成员如下: RxBinder

  • Flutter状态管理Provider示例解析

    目录 什么是状态管理 常见的状态管理框架有哪些 Provider Redux GetX Provider 使用 添加依赖 导入应用 定义需要共享的数据 在应用程序入口初始化 使用共享数据 状态管理的好处 结束语 什么是状态管理 状态管理是一个十分广泛的概念,因为状态无处不在.从广义角度讲状态管理就是页面跟代码.跟服务器进行数据同步.例如:你在某购物应用内,添加了一件商品,你需要在购物车页面进行展示.这就是一种状态.相反的,你在商品页面点击了添加到购物车,却在购物车页面没有发现或者过段时间它才展示

  • Flutter组件状态管理的3种方法

    前言 前面讲了Flutter布局,布局只是静态的.在Flutter中,组件分为StatelesslWidget和StatefulWidget. StatelesslWidget 没有状态,是一成不变的.比如图标,文字,按钮等 StatefulWidget 有状态的组件,页面数据是动态的,或者会随着用户操作变化,比如多选框,文本输入框等. 有状态组件 重点来了,如何使用实现一个有状态的组件呢? 有状态的组件一般由两个类构成,一个StatefulWidget子类和一个State子类. State类包

随机推荐