Code前端首页关于Code前端联系我们

了解和使用 Provider 进行 Flutter 状态管理

terry 2年前 (2023-09-23) 阅读数 71 #移动小程序

1. 为什么需要 Provider 来管理状态

对于数据变更和数据共享,Provider 是

  • Flutter 的代码是 响应式/声明式 需要的。过去,Android/iOS 代码是绝对必要的
  • 响应式代码实际上需要状态管理,也可以理解为数据共享
  • 接口和数据发生变化,因此需要对其进行管理。简单的可以直接在StatefulWidget中进行管理。比较复杂的方式是使用Provider之类的来管理

简单和复杂数据的示例

数据的变化如何被认为是简单的? ——例如PageView组件中的当前页面、复杂动画中的当前进度、BottomNavigationBar中当前选定的选项卡。它们位于小部件树中,小部件树的其他部分不需要访问此状态。不需要反序列化这个状态,也不需要以复杂的方式改变。

Privider 应管理哪些数据更改? 例如,用户选项、登录详细信息、社交应用程序中的通知、电子商务应用程序中的购物车以及新闻应用程序中文章的已读/未读状态

.
.

Flutter 的状态管理包括 ReduxRxhooks 、ScopedModelProvider等,其中Provider官方推荐。

如果你一无所知,官方推荐绝对是你的首选。

2. 使用提供商

嗯,官方推荐提供商。如果你不熟悉,可以先阅读这两篇文章。

provider官方文章

使用provider管理Flutter应用状态


2.1使用步骤

介绍provider

dependencies:
  provider: ^3.1.0
复制代码

使用provider只需3步即可轻松理解:

  • 创建ChangeNotifier继承于ChangeNotifier共享类
  • 设置数据
  • 通过Provider.of(context)和Consumer两种方式获取数据

很简单~

.
.
. 二. 2 最简单的例子 Provider.of(context) 方法

代码如下:

  • 创建共享类,添加增长数据的方法,调用时刷新
  • 调用数据
  • 构建并再次调用,刷新ui

import 'package:flutter/material.dart';

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // 创建 Widget 持有 CounterNotifier 数据
    return ChangeNotifierProvider.value(
      value: CounterNotifier(),
      child: MaterialApp(
        title: 'Privoder Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: ProvidePage(title: 'Provider 测试页面'),
      ),
    );
  }
}

class ProvidePage extends StatelessWidget {
  final String title;

  ProvidePage({Key key, this.title}) : super(key: key);

  @override
  Widget build(BuildContext context) {

    // 获取 CounterNotifier 数据 (最简单的方式)
    final counter = Provider.of<CounterNotifier>(context);

    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              '按下按钮,使数字增长:',
            ),
            Text(
              '${counter.count}',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          counter.increment();
        },
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}


//  核心:继承自ChangeNotifier
// 这种文件本来应该单独放在一个类文件连的
class CounterNotifier with ChangeNotifier {
  int _count = 0;
  int get count => _count;

  increment() {
    _count++;
    // 核心方法,通知刷新UI,调用build方法
    notifyListeners();
  }
}
复制代码

.
.

效果:Flutter状态管理之Provider的理解使用

注意

  • 使用Provider.of。 ChangeNotifier 中调用 notifListeners 时,每次都会调用 Widget 中的 build

。大概就是这样。你可能会说你应该直接设置setState。不,绝对不一样,setState太不灵活了。

.
.
.

2.3 示例 Consumer 方法

示例:在第 1 页设置一个值,然后将其显示在第 2 页(不要问为什么不直接使用 Navigator) , demo 演示,仅供演示)

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

main() {
  runApp(ChangeNotifierProvider<CounterNotifier>.value(
    value: CounterNotifier(),
    child: MyApp(),
  ));
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MultiProvider(
      providers: [
        Provider.value(value: 36),
        ChangeNotifierProvider.value(value: CounterNotifier())
      ],
      child: MaterialApp(
        title: 'Privoder Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: Page1(),
      ),
    );

 }
}

class Page1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    //获取文字大小
    final size = Provider.of<int>(context).toDouble();
    // 获取计数
    final counter = Provider.of<CounterNotifier>(context);
    // 调用 build 时输出
    print('rebuild page 1');
    return Scaffold(
      appBar: AppBar(
        title: Text('Page1'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            // 显示计数
            Text(
              'Current count: ${counter.count}',
              // 设置文字大小
              style: TextStyle(
                fontSize: size,
              ),
            ),
            SizedBox(
              height: 50,
            ),
            // 跳转 Page2
            RaisedButton(
              onPressed: () => Navigator.of(context).push(
                MaterialPageRoute(builder: (context) => Page2()),
              ),
              child: Text('Next'),
            ),
          ],
        ),
      ),
    );
  }
}


class Page2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print('rebuild page 2');
    return Scaffold(
      appBar: AppBar(
        title: Text('Page2'),
      ),
      body: Center(
        child: Consumer2<CounterNotifier, int>(
            builder: (context, counter, size, _) {
              print('rebuild page 2 refresh count');

              return Column(
                mainAxisSize: MainAxisSize.min,
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Text(
                    'You have pushed the button this many times:',
                  ),
                  Text(
                    '${counter.count}',
                    style: TextStyle(
                      fontSize: size.toDouble(),
                    ),
                  ),
                ],
              );
            }),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // 不需要监听改变(listen: false 不会重新调用build)
          Provider.of<CounterNotifier>(context, listen: false).increment();
        },
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}


class CounterNotifier with ChangeNotifier {
  int _count = 0;

  int get count => _count;

  increment() {
    _count++;
    notifyListeners();
  }
}


复制代码

.

  • 1.在第 2 页上,消费者
  • 2。如果 Provider.of 的监听器为 false,则不会再次调用 build

.。 设置第 2 页上的值。返回第 1 页时,第 1 页将显示第 2 页的值 Flutter状态管理之Provider的理解使用

.
.Flutter状态管理之Provider的理解使用

.

比较
  • 触发器(提供商。或) :如果只是需要获取数据模型的话。无需监视更改
(例如单击按钮)。推荐使用Provider.of(context, Listen: false)来获取数据模型。

  • 听(消费者推荐):消费者推荐。
  • 作者:夏日舒适
    链接:https://juejin.im/post/5d77bdf2518825513b537958
    来源:掘金
    版权归作者所有。商业转载请联系作者获得许可。非商业转载请注明出处。

    版权声明

    本文仅代表作者观点,不代表Code前端网立场。
    本文系作者Code前端网发表,如需转载,请注明页面地址。

    发表评论:

    ◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

    热门