Flutter 46: 图解新的状态管理 Provider (一)

简介: 0 基础学习 Flutter,第四十六步:学习 2019 I/O 推出的新的状态管理框架!

      2019 Google I/O 大会上重磅消息出了支持 flutter_web 之外,另一个便是弃用之前的状态管理 Provide,转而推荐相似的库 Provider;虽然只有一个字母之差使用方式差别却很大;小菜初步学习一下新的状态管理库 Provider

      Flutter 针对不同类型对象提供了多种不同的 ProviderProvider 也是借助了 InheritWidget,将共享状态放到顶层 MaterialApp 之上;

Provider 方式

      最基本的状态管理方式,以一个参数方式绑定和展示;

1. 绑定数据

      Provider 可在需要的 Widget 处进行数据绑定:

const Provider.value({
    Key key,
    @required T value,
    this.updateShouldNotify,
    this.child,
})  : dispose = null,
        super.value(key: key, value: value);

      分析源码 Provider.value 并没有限制 value 类型,我们可以根据需求随意绑定需要的数据类型;当我们确定绑定的数据类型时,建议绑定时添加数据类型,如:Provider.value( value: '', child:)

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(primarySwatch: Colors.blue),
        home: Provider<String>.value( value: 'FirstPage Provider', child: MyHomePage(title: 'Peovider Demo')));
  }
}

2. 获取数据

      Provider 需要在数据绑定的子 Widget 中进行获取;使用静态方法 Provider.of(BuildContext context),此方法从 BuildContext 关联的 Widget Tree 中查找最近的相同类型的数据进行展示;没有则报异常;

Text('${Provider.of<String>(context)}'),
Text('FirstPage Provider: ${Provider.of<String>(context)} | ${Provider.of<int>(context)} | ${Provider.of<bool>(context)}}'),

3. 绑定多条数据

      在我们实际开发中不会只绑定一条数据,当绑定多条数据时可以采用如下两种方式:嵌套绑定和聚合绑定;两种方式效果完全相同,小菜更倾向于 MultiProvider 绑定,层级更清晰简洁;

// 嵌套绑定
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(primarySwatch: Colors.blue),
        home: Provider<User>.value(
            value: new User('Flutter', 300),
            child: Provider<int>.value(
                value: 200,
                child: Provider<bool>.value(
                    value: false, child: MyHomePage(title: 'Peovider Demo')))));
  }
}

// 聚合方式
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(primarySwatch: Colors.blue),
        home: MultiProvider(providers: [
          Provider<User>.value(value: new User('Flutter', 300)),
          Provider<int>.value(value: 200),
          Provider<bool>.value(value: false)
        ], child: MyHomePage(title: 'Peovider Demo')));
  }
}

4. 绑定数据类型

      Provider 绑定数据类型比较灵活,并非只是基本数据类型,小菜定义了一个 User 类,可正常状态管理;小菜在获取 User 后重新设置 name 之后获取的 User 为最新的数据;

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(primarySwatch: Colors.blue),
        home: MultiProvider(providers: [
          Provider<User>.value(value: new User('Flutter', 300)),
          Provider<int>.value(value: 200),
          Provider<bool>.value(value: false)
        ], child: MyHomePage(title: 'Peovider Demo')));
  }
}

Text(
    'FirstPage Provider: ${Provider.of<String>(context)} | '
    '${Provider.of<int>(context)} | ${Provider.of<bool>(context)} | ${Provider.of<User>(context).name = 'Hello World!'}',
    style: TextStyle(color: Colors.redAccent)),
Text('${Provider.of<User>(context).name}'),

5. 作用域

      小菜在刚开始学习时被作用域卡到,实际文档说的很明白,获取绑定数据的范围是在绑定数据的子 Widget 中;小菜绘制了一下个人理解的基本作用域图,如有错误请多多指导;

      void main() => runApp() 为范围最广的 application 作用域,其作用范围包括各个 Page 之间;FirstPage 中定义的 Provider A 作用在蓝色框范围内,Provider B 作用在粉色框范围内,SecondPage 中定义的 Provider C 作用在绿色范围内;超出范围则不能进行状态管理;

6. 作用域内容

      如上图作用域划分,在 FirstPage 多个作用域的粉色框中,若获取 String 类型的状态管理 Provider.value( value: '', child:),首先在粉色作用域中查找,若存在则展示粉色框中绑定数据;若没有则查找上一层蓝色作用域,存在则为蓝色框绑定数据;若依然没有查找 application 作用域,存在则展示 application 作用域绑定数据;若均没有则报异常;

      这也验证了文档中提及的子 Widget 作用域,一层一层往外层查找,直到可以正常获取;

ChangeNotifierProvider 方式

      通过调用 ChangeNotifier.notifyListenersChangeNotifier 进行监听,将其公开给它的子 Widget 并重建依赖项;

1. 绑定数据

ChangeNotifierProvider 绑定数据有两种方式:

  1. ChangeNotifierProvider({Key key, @required ValueBuilder builder, Widget child })

      通过构造器创建一个 ChangeNotifier,在 ChangeNotifierProvider 移除时自动处理;

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<User>(
        builder: (_) => User('Flutter', 0),
        child: MaterialApp(
            title: 'Flutter Demo',
            theme: ThemeData(primarySwatch: Colors.blue),
            home: MyHomePage(title: 'Peovider Demo')));
  }
}
  1. ChangeNotifierProvider.value({Key key, @required T notifier, Widget child })

      通过监听通知给子 Widget 并重建依赖项;

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<User>.value(
        notifier: User('Flutter', 0),
        child: MaterialApp(
            title: 'Flutter Demo',
            theme: ThemeData(primarySwatch: Colors.blue),
            home: MyHomePage(title: 'Peovider Demo')));
  }
}

2. 获取数据

      获取数据的方式与直接使用 Provider 相似;

Text('${Provider.of<User>(context).getName}'),

      相对于 ProviderChangeNotifierProvider 方式更加灵活,可以通过重写 get/set 方法来对状态管理进行修改和使用;

// User 实体 Bean
class User with ChangeNotifier {
  var name;
  var age;

  User(this.name, this.age);

  void setName(String name) {
    this.name = name;
    notifyListeners();
  }

  String get getName => this.name;
}
// 绑定 Provider
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<User>(
        builder: (_) => User('Flutter', 0),
        child: MaterialApp(
            title: 'Flutter Demo',
            theme: ThemeData(primarySwatch: Colors.blue),
            home: MyHomePage(title: 'Peovider Demo')));
  }
}
// 获取 Provider 数据
Expanded(
    child: TextField(
        onChanged: (changed) =>
            Provider.of<User>(context).setName(changed),
        controller: _phonecontroller,
        decoration: InputDecoration(
            hintText: '请输入用户名',
            suffixIcon: IconButton(
                icon: Icon(Icons.clear,
                    color: Colors.black45),
                onPressed: () {
                  _phonecontroller.clear();
                })))),
Text('${Provider.of<User>(context).getName}'),

问题小结

      小菜在开始尝试时总是遇到如下问题,Could not find the correct Provider... 测试后了解是在子 Widget 中层级查找未找到对应的绑定数据;极有可能是绑定数据的 Widget 位置未绑定或绑定位置错误;


      小菜对 Provider 的理解还很浅显,对于其他 Provider 的使用还未尝试;如有错误请多多指导!

目录
相关文章
|
2月前
|
存储 JavaScript 前端开发
盘点主流 Flutter 状态管理库2024
状态管理是每个应用不可缺少的,本文将会盘点下主流的状态管理包。
盘点主流 Flutter 状态管理库2024
|
6月前
|
Dart Android开发 UED
带你读《深入浅出Dart》二十七、Flutter路由管理
带你读《深入浅出Dart》二十七、Flutter路由管理
|
7月前
|
存储 Dart 数据库
重识Flutter状态管理 — 探索Flutter中的状态
我遇到过很多没有了解过响应式编程框架的,或者从事后端开发,自己想用Flutter写个app玩玩的朋友,一上来,不管在哪里都用`setState`,我问为啥不用状态管理,大部分都回了一句:啥是状态管理?
|
7月前
|
存储 数据库 索引
Flutter笔记:滚动之-无限滚动与动态加载的实现(GetX简单状态管理版)
本文介绍Flutter中如何实无线滚动(基于GetX简单状态管理而非有状态组件)
69 0
|
4月前
|
Dart
Flutter状态管理:RxDart,详细介绍
Flutter状态管理:RxDart,详细介绍 RxDart是一个基于Dart语言的响应式编程库,它提供了一套用于处理异步事件序列的工具。在Flutter应用中,RxDart可以很好地用于管理应用状态。
|
4月前
|
存储 前端开发
Flutter Provider状态管理---MVVM架构实战
Flutter Provider状态管理—MVVM架构实战 在Flutter中,状态管理是一个非常重要的概念。Flutter Provider是一种状态管理的解决方案,它提供了一种简单,灵活和高效的方法来管理Flutter应用程序中的状态。本文将详细介绍Flutter Provider的使用,以及如何在MVVM架构中使用它。
155 0
|
3月前
|
Linux 开发者 iOS开发
Flutter笔记:桌面端应用多窗口管理方案
Flutter笔记:桌面端应用多窗口管理方案
119 0
|
3月前
|
编解码 缓存 调度
Flutter笔记:Flutter的应用生命周期状态(lifecycleState)管理
Flutter笔记:Flutter的应用生命周期状态(lifecycleState)管理
76 0
|
9月前
|
缓存 Dart 前端开发
Flutter 中使用 Widgetbook 管理你的组件 | 猫哥
Flutter 界面开发中我们有几个痛点 : - 与设计师协作复用一套设计规范(figma) - 可视化的管理你的组件代码(基础组件、业务组件) - 不同设备尺寸测试你的组件 - 实时修改你的测试组件参数
4212 1
Flutter 中使用 Widgetbook 管理你的组件 | 猫哥
|
4月前
|
API
Flutter状态管理终极方案GetX第一篇——路由
Flutter状态管理终极方案GetX第一篇——路由 GetX是Flutter中一个非常流行的状态管理库,它不仅提供了简单易用的状态管理功能,还可以帮助我们方便地管理路由。在这篇文章中,我们将介绍如何使用GetX来实现路由管理。
142 0