flutter状态管理案例

发布时间 2023-07-14 14:55:48作者: hztech

 

FLUTTER项目中管理不同组件、不同页面之间共享的数据关系。当需要共享的数据关系达到几十上百个的时候,我们就很难保持清晰的数据流动方向和顺序了,导致应用内各种数据传递嵌套和回调满天飞。在这个时候,我们迫切需要一个解决方案,来帮助我们理清楚这些共享数据的关系,于是状态管理框架便应运而生。

 

下面来了解一下如何使用Provider进行状态管理,使用步骤如下:

1、首先安装Provider   flutter pub get

dependencies:
  flutter:
    sdk: flutter
  provider: 6.0  #provider依赖

 

2、将需要共享的状态进行封装 就是类封装

//定义需要共享的数据模型,通过混入ChangeNotifier管理听众
class CounterModel with ChangeNotifier {
  int _count = 0;
  //读方法
  int get counter => _count; 
  //写方法
  void increment() {
    _count++;
    notifyListeners();//通知听众刷新
  }
}

这个类需要混入ChangeNotifier。这个类能够帮助我们管理所有依赖资源封装类的听众。当资源封装类调用 notifyListeners 时,它会通知所有听众进行刷新。

3、将封装的状态放在组件最高层,因为 Provider 实际上是 InheritedWidget 的语法糖,所以通过 Provider 传递的数据从数据流动方向来看,是由父到子(或者反过来),所以一般就是把资源放到更高的层级。需要注意的是是如何放。

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
     //通过Provider组件封装数据资源
    return ChangeNotifierProvider.value(
        value: CounterModel(),//需要共享的数据资源
        child: MaterialApp(
          home: FirstPage(),
        )
    );
  }
}

 

因为 provider 是一个 Widget。所以,我们直接在 MaterialApp 的外层使用 Provider 进行包装,就可以把数据资源依赖注入到应用中,这里需要注意的是,由于封装的数据资源不仅需要为子 Widget 提供读的能力,还要提供写的能力,因此我们需要使用 Provider 的升级版 ChangeNotifierProvider。而如果只需要为子 Widget 提供读能力,直接使用 Provider 即可。

4、在子组件中通过of方法获取属性与方法,部署状态。

//第一个页面,负责读数据
class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    //取出资源
    final _counter = Provider.of<CounterModel>(context);
    return Scaffold(
      //展示资源中的数据
      body: Text('Counter: ${_counter.counter}'),
      //跳转到SecondPage
      floatingActionButton: FloatingActionButton(
        onPressed: () => Navigator.of(context).push(MaterialPageRoute(builder: (context) => SecondPage()))
      ));
  }
}

//第二个页面,负责读写数据
class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    //取出资源
    final _counter = Provider.of<CounterModel>(context);
    return Scaffold(
      //展示资源中的数据
      body: Text('Counter: ${_counter.counter}'),
      //用资源更新方法来设置按钮点击回调
      floatingActionButton:FloatingActionButton(
          onPressed: _counter.increment,
          child: Icon(Icons.add),
     ));
  }
}

 

另一个例子

 

import 'package:flutter/material.dart';

class Datashare extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
      children: [App1(), App2()],
    );
  }
}

class App1 extends StatelessWidget {
  // 获取属性与方法

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 100,
      height: 100,
      color: Colors.yellow,
      child: Text("111"),
    );
  }
}

class App2 extends StatelessWidget {
  // 获取属性与方法
  
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 100,
      height: 100,
      color: Colors.redAccent,
      child: FlatButton(child: Text("加一"),color: Colors.redAccent,onPressed: ()=>{

      })
    );
  }
}

 

改造成支持provider   的代码

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

// 封装状态:
class CountContainer with ChangeNotifier {
  int _count = 0;
  int get counter => _count;

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

// class Datashare extends StatelessWidget {
//   @override
//   Widget build(BuildContext context) {
//     return Row(
//       children: [App1(), App2()],
//     );
//   }
// }

// 将封装的装填放到顶层组件;

class Datashare extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider.value(
        value: CountContainer(),
        child: Row(
          children: [App1(), App2()],
        ));
  }
}

class App1 extends StatelessWidget {
  // 获取属性与方法

  @override
  Widget build(BuildContext context) {
    final _counter = Provider.of<CountContainer>(context);
    print(_counter);
    return Container(
      width: 100,
      height: 100,
      color: Colors.yellow,
      child: Text('${_counter._count}'),
    );
  }
}

class App2 extends StatelessWidget {
  // 获取属性与方法

  @override
  Widget build(BuildContext context) {
    final _counter = Provider.of<CountContainer>(context);
    return Container(
        width: 100,
        height: 100,
        color: Colors.redAccent,
        child: FlatButton(
            child: Text("加一"),
            color: Colors.redAccent,
            onPressed: () => {
                _counter.increment()
            }));
  }
}

 

 

5、多个状态 共享 

数据状态的共享。

此时我么需要MultiProvider,我们修改上面的代码,注入一个只读的数字,这个数字只做展示,局部代码如下

 

class Datashare extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(providers: [
      Provider.value(value: 30.0),
      ChangeNotifierProvider.value(
          value: CountContainer(),
          )
    ],
    child: Row(
            children: [App1(), App2()],
          ));
  }
}

class App1 extends StatelessWidget {
  // 获取属性与方法

  @override
  Widget build(BuildContext context) {
    final _counter = Provider.of<CountContainer>(context);
    final textSize = Provider.of<double>(context);
    print(_counter);
    return Container(
      width: 100,
      height: 100,
      color: Colors.yellow,
      child: Text('${_counter._count}----$textSize'),
    );
  }
}