(译)Flutter bloc包

栏目: Android · 发布时间: 5年前

内容简介:在使用Flutter一段时间之后,我决定创造一个包帮忙我经常使用的东西—BLoC模式做一些事情。

原文链接

(译)Flutter bloc包

在使用Flutter一段时间之后,我决定创造一个包帮忙我经常使用的东西—BLoC模式做一些事情。

对于那些不熟悉BLoC模式的人来说,它是一种设计模式,它有助于将表示层与业务逻辑分开。你从 这里 能够了解更多。

虽然使用BLoC模式可能会因为设置以及对 StreamsReactive Programming 的理解而具有挑战性,但它的核心BLoC是非常简单的:

BLoC将事件流作为输入,并将它们转换为状态流作为输出。

(译)Flutter bloc包

我们现在可以在bloc包的帮助下使用这种强大的设计模式。

该软件包抽象了BLoC模式的响应式方面,允许开发人员专注于将事件转换为状态。

让我们从定义这些术语开始。

词汇表

事件( Events )是BLoC的输入。它们通常是UI事件,例如按钮按下。事件( Events )被发送( dispatched )并转换为状态( States )。

状态( State )是BLoC的产物。表示组件可以监听状态流并根据给定状态对其自身的部分进行重绘(有关详细信息,请参阅 BlocBuilder )。

转换( Transitions )发生在mapEventToState被调用之后,当事件被发送之后,但在bloc状态被修改之前。一个转换( Transition )由当前状态( currentState ),已分送的事件( event )和下个状态( nextState )组成。

现在我们了解事件和状态,我们可以看一下Bloc API了。

Bloc API

mapEventToState是一个类在扩展Bloc时必须实现的方法。该方法将传入事件作为参数。只要有一个事件被表示层发送( dispatched ),就会调用 mapEventToStatemapEventToState 必须将该事件转换为新状态,并 Stream 的形式返回新状态,而这个新状态会被表示层使用。

dispatch 是一个接收事件并触发 mapEventToState 的方法。可以从表示层或从Bloc内部调用dispatch(参见示例)并向Bloc通知新事件来了。

initialState 是任何事件都没有被处理之前的状态(在调用 mapEventToState 之前)。initialState是一个可选的getter。如果未实现,则initialState将为null。

transform 是一个方法,可以在调用 mapEventToState 之前重写Stream 。这其中允许使用distinct()和debounce()之类的操作。

onTransition 是一个方法,可以在发生转换时覆盖对其加以处理。转换( Transition )发生在新的事件( event )被发送以及 mapEventToState 被调用的时候。 onTransition 在bloc的状态被更新之前被调用。这是添加bloc特有的日志记录/分析的好地方。

让我们创建一个计数器bloc!

enum CounterEvent { increment, decrement }

class CounterBloc extends Bloc<CounterEvent, int> {
  @override
  int get initialState => 0;

  @override
  Stream<int> mapEventToState(CounterEvent event) async* {
    switch (event) {
      case CounterEvent.decrement:
        yield currentState - 1;
        break;
      case CounterEvent.increment:
        yield currentState + 1;
        break;
    }
  }
}

为了创建一个计数器bloc,我们需要做的就是:

  • 定义我们的事件和状态
  • 扩展BloC
  • 覆盖 initialStatemapEventToState

在这种情况中,我们的事件是 CounterEvents ,我们的状态是整数类型。

我们的 CounterBlocCounterEvents 转换为整数类型。

我们可以通过像这样调用 dispatch 方法来通知CounterBloc发出事件:

void main() {
  final counterBloc = CounterBloc();

  counterBloc.dispatch(CounterEvent.increment);
  counterBloc.dispatch(CounterEvent.decrement);
}

为了观察状态变化( Transitions ),我们可以覆盖 onTransition

enum CounterEvent { increment, decrement }

class CounterBloc extends Bloc<CounterEvent, int> {
  @override
  int get initialState => 0;
  
  @override
  void onTransition(Transition<CounterEvent, int> transition) {
    print(transition);
  }

  @override
  Stream<int> mapEventToState(CounterEvent event) async* {
    switch (event) {
      case CounterEvent.decrement:
        yield currentState - 1;
        break;
      case CounterEvent.increment:
        yield currentState + 1;
        break;
    }
  }

现在,每当我们调度CounterEvent时,我们的Bloc将以新的整数状态响应,我们将看到一个转换记录被打印到到控制台。

现在让我们使用Flutter构建一个UI,并使用 flutter_bloc 包将表示层连接到我们的 CounterBloc

flutter_bloc 包提供了两个widget,使得可以轻松地与Bloc进行交互:

BlocBuilder

BlocBuilder 是一个Flutter widget,它需要一个Bloc和一个builder方法。 BlocBuilder处理了构建widget的工作以响应新状态。BlocBuilder与StreamBuilder非常相似,但它有一个更简单的API来减少所需的样板代码量。

BlocProvider

BlocProvider 是一个Flutter widget,它通过 BlocProvider.of(context) 为其子节点提供一个集合。它被用作依赖注入(DI)widget,以便可以将BloC的单例提供给子树中的多个widget。

现在让我们构建我们的Counter App!

class App extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _AppState();
}

class _AppState extends State<App> {
  final CounterBloc _counterBloc = CounterBloc();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: BlocProvider<CounterBloc>(
        bloc: _counterBloc,
        child: CounterPage(),
      ),
    );
  }

  @override
  void dispose() {
    _counterBloc.dispose();
    super.dispose();
  }
}

class CounterPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final CounterBloc _counterBloc = BlocProvider.of<CounterBloc>(context);

    return Scaffold(
      appBar: AppBar(title: Text('Counter')),
      body: BlocBuilder<CounterEvent, int>(
        bloc: _counterBloc,
        builder: (BuildContext context, int count) {
          return Center(
            child: Text(
              '$count',
              style: TextStyle(fontSize: 24.0),
            ),
          );
        },
      ),
      floatingActionButton: Column(
        crossAxisAlignment: CrossAxisAlignment.end,
        mainAxisAlignment: MainAxisAlignment.end,
        children: <Widget>[
          Padding(
            padding: EdgeInsets.symmetric(vertical: 5.0),
            child: FloatingActionButton(
              child: Icon(Icons.add),
              onPressed: () {
                _counterBloc.dispatch(CounterEvent.increment);
              },
            ),
          ),
          Padding(
            padding: EdgeInsets.symmetric(vertical: 5.0),
            child: FloatingActionButton(
              child: Icon(Icons.remove),
              onPressed: () {
                _counterBloc.dispatch(CounterEvent.decrement);
              },
            ),
          ),
        ],
      ),
    );
  }
}

我们的App widget是 StatefulWidget ,负责创建和处理CounterBloc。它使用我们上面提到的BlocProvider widget使CounterBloc可用于CounterPage widget。

我们的 CounterPage widget是一个 StatelessWidget ,它使用 BlocBuilder 重建UI以响应 CounterBloc 的状态变化。

此时,我们已经成功地将我们的表示层与业务逻辑层分开。请注意,CounterPage widget 不知道用户点击按钮时会发生什么。widget只是告诉CounterBloc用户按下了递增或递减按钮。

就这么多。

有关更多示例和详细文档,请查看 官方bloc文档

如果你喜欢这个bloc库,你可以通过:star:️ 仓库 或者:clap:来支持我这个文章。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Fortran 95/2003程序设计

Fortran 95/2003程序设计

中国电力出版社 / 2009-8 / 88.00元

Fortran是计算世界最早出现的高级程序设计语言之一,随着面向对象编程时代的到来,Fortran语言不仅保持了发展的步伐,而且继续在科学计算方面领先。《Fortran95/2003程序设计(第3版)》在第2~7章介绍了Fortan语言基础知识,为初学者提供入门学习资料;在第8~15章介绍了Fortran语言高级特性,为深入用好Fortran语言提供支持;在第16章讲述了Fortran语言面向对象......一起来看看 《Fortran 95/2003程序设计》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换