• Flutter基础--状态管理


    当我们使用编译器创建一个新Flutter应用的时候,我们可以在主界面看到两个小部件StatelessWidget和StatefulWidget。这是两个最常见使用最频繁的小部件了。

    StatelessWidget ,StatefulWidget

    1. StatelessWidget 状态不可改变的,它内部的数值和UI都应该是常量不可改变
    2. StatefulWidget 状态可变,我们可以通过点击,或者网络获取数据等来动态的改变界面。

    假如我们要实现如下图的功能,点击加一。如果使用StatelessWidget,会发现点击的时候count是加一了,但是界面没有刷新。应该使用StatefulWidget,当count加一的时候通过 setState(() { _count++;}); 方法来改变count的值,这时候就发现界面可以刷新了。

    比如

    import 'package:flutter/material.dart';
    
    class StateManagerDemo extends StatefulWidget {
      @override
      _StateManagerDemoState createState() => _StateManagerDemoState();
    }
    
    class _StateManagerDemoState extends State<StateManagerDemo> {
      int _count = 0;
      void countCallBack(){
        setState(() {
          _count++;
        });
        debugPrint('$_count');
      }
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('StateManagerDemo'),
            elevation: 0.0,
          ),
          body: Counter0(_count),
          floatingActionButton: FloatingActionButton(
            child: Icon(Icons.add),
            onPressed: countCallBack,
          ),
        );
      }
    }
    //------
    class Counter0 extends StatelessWidget {
      final int count;
      Counter0(this.count);
      @override
      Widget build(BuildContext context) {
        return Center(
          child: Chip(
            label: Text('$count'),
          ),
        );
      }
    }
    //-----
    class Counter extends StatelessWidget {
      final int count;
      final VoidCallback voidCallback;
      Counter(this.count,this.voidCallback);
      @override
      Widget build(BuildContext context) {
        return Center(
          child: ActionChip(
            label: Text('$count'),
            onPressed: voidCallback,
          ),
        );
      }
    }
    

    上面的代码中,StateManagerDemo有两个子部件Counter0和Counter。当我们点击按钮的时候,_count的值++,然后传递给子部件。

    Counter0是直接接受父部件传过来的参数。

    Counter不仅接收父部件传过来的参数,还有一个回调。这样点击它的时候,会执行父部件中的回调方法,也能改变自身的显示。

    InheritedWidget

    上面的情况是只有一层,比如Counter小部件中使用了父部件的count这个变量,假如Counter没有用到这个变量而是它的子类用到了这个变量,我们还要一层一层的传下去吗,这有点麻烦啊,这时候可以使用InheritedWidget这个类来管理。

    import 'package:flutter/material.dart';
    
    //使用InheritedWidget来管理状态,
    class ContentProvider extends InheritedWidget {
      final int count;
      final VoidCallback countCallBack;
      final Widget child;
      const ContentProvider({
        this. count,
         this. countCallBack,
        this. child,
      }): assert(child != null),
            super(child: child);
    
      static ContentProvider of(BuildContext context) {
        return context.inheritFromWidgetOfExactType(
            ContentProvider) as ContentProvider;
      }
      //是否通知继承该小部件的小部件更新
      @override
      bool updateShouldNotify(ContentProvider old) {
        return true;
      }
    }
    class StateManagerDemo extends StatefulWidget {
      @override
      _StateManagerDemoState createState() => _StateManagerDemoState();
    }
    
    class _StateManagerDemoState extends State<StateManagerDemo> {
      int _count = 0;
      void countCallBack(){
        setState(() {
          _count++;
        });
        debugPrint('$_count');
      }
      @override
      Widget build(BuildContext context) {
      //ContentProvider放在最外层,指定参数count和callback
        return ContentProvider(
          count: _count,
          countCallBack: countCallBack,
          child: Scaffold(
            appBar: AppBar(
              title: Text('StateManagerDemo'),
              elevation: 0.0,
            ),
            body: Counter1(),
            floatingActionButton: FloatingActionButton(
              child: Icon(Icons.add),
              onPressed: countCallBack,
            ),
          ),
        );
      }
    }
    
    class Counter1 extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        //直接使用ContentProvider中的参数
        final int count = ContentProvider.of(context).count;
        final VoidCallback voidCallback = ContentProvider.of(context).countCallBack;
        return Center(
          child: ActionChip(
            label: Text('$count'),
            onPressed: voidCallback,
          ),
        );
      }
    }
    

    首先定义一个数据提供者ContentProvider继承InheritedWidget,里面定义我们需要的count和回调。提供一个of方法让外界可以拿到它的实例,方便拿到方法。

    然后将这个ContentProvider放在主布局的最外层,并传入需要的参数count和callBack。这样它的子部件中就都能访问到这个参数了。

    最后在子部件Counter1中直接使用ContentProvider中的参数。

    ScopedModel

    还可以使用ScopedModel来完成状态管理

    这是一个第三方的库,该库最初是从Fuchsia代码库中提取的,使用时需要先导入包,在pubspec.yaml文件中添加依赖

    dependencies:
       scoped_model: 1.0.1
    

    https://pub.dev/packages?q=scoped_model 这里可以看到最新版本。使用这个库的时候我们在StatelessWidget中也可以改变UI

    该库主要分为三个部分

    1. Model class 扩展此类以创建自己的模型,例如SearchModel或UserModel。我们可以监听数据的变化!
    2. ScopedModel 小部件 把Model包装到ScopedModel中,它内部的所有部件都能拿到model中的数据
    3. ScopedModelDescendant 只要Model发生改变 它就会改变

    比如用ScopedModel实现前面的功能

    import 'package:flutter/material.dart';
    import 'package:scoped_model/scoped_model.dart';
    
    class CountModel extends Model{
       int _count = 0;
       int get count =>_count;
    
       void countIncrease(){
         _count ++;
         //通知改变
         notifyListeners();
       }
    }
    
    class StateModelDemo extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return ScopedModel<CountModel>(
          model: CountModel() ,
          child: Scaffold(
            appBar: AppBar(
              title: Text('StateModelDemo'),
            ),
            body: Counter2(),
            floatingActionButton: ScopedModelDescendant<CountModel>(
              rebuildOnChange: false,
              builder: (context, child, model) => FloatingActionButton(
                child: Icon(Icons.add),
                onPressed: (){
                  model.countIncrease();
                },
              ),
            ),
          ),
        );
      }
    }
    
    class Counter2 extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return ScopedModelDescendant<CountModel>(
          builder: (context, child, model) => Center(
            child: ActionChip(
              label: Text('${model.count}'),
              onPressed: (){
                model.countIncrease();
              },
            ),
          ),
        );
      }
    }

    Mobx

    Mobx在前端中用的多,且很好用,所以Flutter也引入了,对于我们Android开发者来说跟学前面的成本都一样哈哈。

    广州VI设计公司https://www.houdianzi.com

    首先需要去pubspec.yaml文件中引入依赖

    dependencies:
      mobx: ^0.3.8
      flutter_mobx: ^0.3.3
    dev_dependencies:
      mobx_codegen: ^0.3.9
      build_runner: ^1.7.0
    

    然后开始使用mobx完成之前的功能

    首先创建一个store类

    import 'package:mobx/mobx.dart';
    //包含生成的文件
    part 'state_manager_demo.g.dart';
    
    class Counter = _Counter3 with _$Counter;
    
    abstract class _Counter3 with Store {
      @observable
      int value = 0;
    
      @action
      void increment() {
        value++;
      }
    }
    

    创建完成之后,我们会发现part后面的内容和_$Counter都会报错。说是找不到,需要我们生成。来到AndroidStudio的terminal窗口执行下面命令来生成文件

    flutter packages pub run build_runner build
    

    这时候就可以看到我们自己的文件state_manager_demo.dart文件旁边生成了一个新文件state_manager_demo.g.dart,而且不在报错了。

    如果想要修改后.g.dart文件也能自动修改执行

    pub run build_runner watch
    

    下面去界面中使用它

    class MobxDemo extends StatefulWidget {
      @override
      _MobxDemoState createState() => _MobxDemoState();
    }
    
    class _MobxDemoState extends State<MobxDemo> {
      final Counter counter = Counter();
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('StateModelDemo'),
          ),
    
          body: Center(
            child: Observer(
                builder: (_)=>ActionChip(
                  label: Text('${counter.value}'),
                  onPressed: (){
                    counter.increment();
                  },
                ),
            ),
          ),
    
          floatingActionButton: FloatingActionButton(
            child: Icon(Icons.add),
            onPressed:(){
              counter.increment();
            },
          ),
        );
      }
    }
    

    很简单继承StatefulWidget,需要监听的小部件使用Observer包裹起来。然后创建一个成员变量 final Counter counter = Counter(); 内部就可以直接使用Counter中的变量和方法了。运行效果跟前面的一样。

    综合来看这几种状态管理的方式 ,我感觉Mobx是最好用的一个。

  • 相关阅读:
    Spark学习之Spark Core
    Druid
    Spark学习之scala编程
    大数据学习之Zookeeper
    大数据学习之HBase
    大数据学习之Yarn
    大数据学习之Mapreduce
    运行spark sql时出现的一个问题
    大数据学习之Hive 简介安装与基本练习
    mysql
  • 原文地址:https://www.cnblogs.com/qianxiaox/p/14025615.html
Copyright © 2020-2023  润新知