OpenFlutter/Flutter-Notebook

建议采用经典的counter 作为BLoC的例子

Closed this issue · 4 comments

下面的例子是按照 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

谢谢!非常棒建议!我知道现在库中的BLoC是我做的一个不太好的例子😅,事实上我正准备将这个demo替换成Count demo,这两天我正在把Stream和BLoC整理成文章。
你写的count bloc我认为真的很棒,我会在新的demo中参考它!😉

我刚才将你发的代码提交了bloc provider pattern😘

@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();
  }
}

ok,老哥你本地改一下跑了没问题就提pr吧