Flutter学习(一) 状态管理

在flutter中有个新概念:BLOC
它是一种利用reactive programming方式构建应用的方法,这是一个由构成的完全异步的世界。先解释一下什么是

流:

即Stream,用现实生活的例子就是一个带有两端的管道,只有一个允许在其中插入一些东西。当你将某物插入管道时,它会在管道内流动并从另一端流出。
其实它是为处理异步事件而生的。
在这里插入图片描述

  • 这个大机器就是StreamController,它是创建流的方式之一。
  • StreamController有一个入口,叫做sink
  • sink可以使用add方法放东西进来,放进去以后就不再关心了。
  • 当有东西从sink进来以后,我们的机器就开始工作啦,空空空。
  • StreamController有一个出口,叫做stream
  • 机器处理完毕后就会把产品从出口丢出来,但是我们并不知道什么时候会出来,所以我们需要使用listen方法一直监听这个出口。
  • 而且当多个物品被放进来了之后,它不会打乱顺序,而是先入先出。

很像观察者模式,有个监听者一直监听着出口,一旦有改变的数据流出,就做出业务改变。也很像vue的双向数据绑定。

BLoC:

BLoC是一种利用reactive programming方式构建应用的方法,这是一个由流构成的完全异步的世界。
在这里插入图片描述

  • 用StreamBuilder包裹有状态的部件,streambuilder将会监听一个流
  • 这个流来自于BLoC
  • 有状态小部件中的数据来自于监听的流。
  • 用户交互手势被检测到,产生了事件。例如按了一下按钮。
  • 调用bloc的功能来处理这个事件
  • 在bloc中处理完毕后将会把最新的数据add进流的sink中
  • StreamBuilder监听到新的数据,产生一个新的snapshot,并重新调用build方法
  • Widget被重新构建

实现

下面的例子其实都是https://www.jianshu.com/p/7573dee97dbb中的例子,单纯想记录一下
在这里插入图片描述

1. main.dart:

import 'package:flutter/material.dart';
import 'package:flutter_bloctest/BlocProvider.dart';
import 'package:flutter_bloctest/TopPage.dart';

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

class MyApp extends StatelessWidget{  //statelessWidget是没有状态的控件,与statefulWidget相对
  @override
  Widget build(BuildContext context) {
    return BlocProvider(  //BlocProvider是自己写的代码
      child: MaterialApp( //继承自StatefulWidget,一个封装了很多所必须要的组件的小部件,一般作为顶层widget使用
        title: 'scoped',
        theme: ThemeData.dark(),
        home: TopPage(),  //一般在MaterialApp的home我们会放一个Scaffold,可以看到TopPage就是return一个Scaffold的
      ),
    );
  }
}
  1. CountBLoC.dart:
import 'dart:async';

import 'package:flutter/material.dart';

//创建一个bloc
class CountBLoC {
  int _count;
  StreamController<int> _countController;

  CountBLoC() {
    _count = 0;

    /*注册一个int类型的StreamController
    这里broadcast是因为一个单订阅流不能有多个收听者,
    我们的app中有2个页面都需要监听这个数据,所以需要将其转为广播流。
    “广播流允许任意数量的收听者,且无论是否有收听者,他都能产生事件。
    所以中途进来的收听者将不会收到之前的消息。”
     */
    _countController = StreamController<int>.broadcast();
  }

  Stream<int> get stream => _countController.stream;  //暴露出流
  int get value => _count;  //暴露出value

  increment() {
    _countController.sink.add(++_count);  //把新数据add进流的sink中
  }

  dispose() {
    _countController.close(); //关闭流
  }
}
  1. BlocProvider.dart:
 import 'package:flutter/material.dart';

import 'CountBLoC.dart';

/*
InheritedWidget是Flutter的一个功能型的Widget基类,
它能有效地将数据在当前Widget树中向它的子widget树传递。
 */
class BlocProvider extends InheritedWidget {
  @override
  CountBLoC bloc = CountBLoC();

  BlocProvider({Key key, Widget child}) : super(key: key, child: child);

//用于控制刷新时机
  @override
  bool updateShouldNotify(InheritedWidget oldWidget) {
    // TODO: implement updateShouldNotify
    return false;
  }

  /*of方法,用于获取到bloc
  它的子Widget树可以通过 BuildContext.inheritedFromWidgetOfExactType()方法获得最近的指定类型的Inherited widget,
  进而获取它的共享数据
   */
  static CountBLoC of(BuildContext context) =>
      (context.inheritFromWidgetOfExactType(BlocProvider) as BlocProvider).bloc;

}

4. TopPage.dart:

 import 'package:flutter/material.dart';
import 'package:flutter_bloctest/BlocProvider.dart';
import 'package:flutter_bloctest/UnderPage.dart';

class TopPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    final bloc = BlocProvider.of(context);  //检索bloc
    return Scaffold(
      appBar: AppBar(
        title: Text('Top Page'),
      ),
      body: Center(
        /*
        StreamBuilder其实是一个StatefulWidget,它通过监听stream,发现有数据输出时,
        自动重建,调用builder方法
         */
        child: StreamBuilder<int>(
            stream: bloc.stream,
            initialData: bloc.value,//获取初始化的值
            builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
              return Text(
                'You hit me:${snapshot.data} times',  //取出data
                style: Theme.of(context).textTheme.display1,  //小字体,display2是中字体...
              );
            }),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.navigate_next),
        //跳到下个页面
        onPressed: ()=>Navigator.of(context).push(MaterialPageRoute(builder: (context)=>UnderPage())),
      ),
    );
  }
}

5. UnderPage:

import 'package:flutter/material.dart';
import 'package:flutter_bloctest/BlocProvider.dart';


class UnderPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final bloc = BlocProvider.of(context);
    print("build");
    return Scaffold(
      appBar: AppBar(
        title: Text('Under Page'),
      ),
      body: Center(
        child: StreamBuilder<int>(
            stream: bloc.stream,
            initialData: bloc.value,
            builder: (BuildContext context, AsyncSnapshot<int> snapshot) => Text(
                  "You hit me : ${snapshot.data} times",
                  style: Theme.of(context).textTheme.display1,
                )),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => bloc.increment(),  //调用添加value的那个函数
        child: Icon(Icons.add),
      ),
    );
  }
}

附上github:https://github.com/aopo1104/flutterLearn

参考资料:

https://element.eleme.cn/#/zh-CN/component/icon
https://www.jianshu.com/p/7573dee97dbb
https://www.jianshu.com/p/346dc2a8cbde

发布了57 篇原创文章 · 获赞 3 · 访问量 6190

猜你喜欢

转载自blog.csdn.net/qq_39830579/article/details/103643888