建议采用经典的counter 作为BLoC的例子
Closed this issue · 4 comments
jonahfang commented
下面的例子是按照 https://www.didierboelens.com/2018/08/reactive-programming---streams---bloc/ 中的**设计的,解决了下列问题: a.提供通用的BLoC provider类;b.解决了BLoC dispose问题.
main.dart
import 'package:flutter/material.dart';
import './bloc_base.dart';
import './bloc_increment.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Streams Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: BlocProvider<IncrementBloc>(
bloc: IncrementBloc(),
child: CounterPage(),
),
);
}
}
class CounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final IncrementBloc bloc = BlocProvider.of<IncrementBloc>(context);
return Scaffold(
appBar: AppBar(title: Text('Stream version of the Counter App')),
body: Center(
child: StreamBuilder<int>(
stream: bloc.outCounter,
initialData: 0,
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
return Text('You hit me: ${snapshot.data} times');
}),
),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.add),
onPressed: () {
bloc.incrementCounter();
},
),
);
}
}
//EOP
bloc_increment.dart
import 'dart:async';
import './bloc_base.dart';
class IncrementBloc implements BlocBase {
int _counter;
//
// Stream to handle the counter
//
StreamController<int> _counterController = StreamController<int>();
StreamSink<int> get _inAdd => _counterController.sink;
Stream<int> get outCounter => _counterController.stream;
//
// Stream to handle the action on the counter
//
StreamController _action = StreamController();
//StreamSink get incrementCounter => _action.sink;
//
// Constructor
//
IncrementBloc() {
_counter = 0;
_action.stream.listen(_handleLogic);
}
incrementCounter() {
_action.sink.add(null);
}
void _handleLogic(data) {
_counter = _counter + 1;
_inAdd.add(_counter);
}
void dispose() {
_action.close();
_counterController.close();
}
}
//EOP
bloc_base.dart
import 'package:flutter/material.dart';
// Generic Interface for all BLoCs
abstract class BlocBase {
void dispose();
}
// Generic BLoC provider
class BlocProvider<T extends BlocBase> extends StatefulWidget {
BlocProvider({
Key key,
@required this.child,
@required this.bloc,
}) : super(key: key);
final T bloc;
final Widget child;
@override
_BlocProviderState<T> createState() => _BlocProviderState<T>();
static T of<T extends BlocBase>(BuildContext context) {
final type = _typeOf<BlocProvider<T>>();
BlocProvider<T> provider = context.ancestorWidgetOfExactType(type);
return provider.bloc;
}
static Type _typeOf<T>() => T;
}
class _BlocProviderState<T> extends State<BlocProvider<BlocBase>> {
@override
void dispose() {
widget.bloc.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return widget.child;
}
}
//EOP
Vadaski commented
谢谢!非常棒建议!我知道现在库中的BLoC是我做的一个不太好的例子😅,事实上我正准备将这个demo替换成Count demo,这两天我正在把Stream和BLoC整理成文章。
你写的count bloc我认为真的很棒,我会在新的demo中参考它!😉
Vadaski commented
我刚才将你发的代码提交了bloc provider pattern😘
jonahfang commented
@Vadaski 今天重新阅读IncrementBloc类,感觉可以取消_action StreamController,简化为:
class IncrementBloc implements BlocBase {
int _counter;
StreamController<int> _counterPipe = StreamController<int>();
Stream<int> get outCounter => _counterPipe.stream;
IncrementBloc() {
_counter = 0;
}
incrementCounter() {
_counter = _counter + 1;
_counterPipe.sink.add(_counter);
}
void dispose() {
_counterPipe.close();
}
}
Vadaski commented
ok,老哥你本地改一下跑了没问题就提pr吧