在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的
),
);
}
}
- 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(); //关闭流
}
}
- 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