likes
comments
collection
share

Flutter学习 - Bloc - 04 Bloc的使用

作者站长头像
站长
· 阅读数 4

本文主要介绍下Bloc的使用和介绍以及和Cubit的区别

之前我们介绍了使用Cubit来处理数据,那么Bloc呢?

1. Bloc

Bloc相比Cubit是一个更高的类,Cubit我们知道通过公开触发状变化的函数。而Bloc依赖事件来床触发状态的改变,Bloc页拓展了BlocBase,所有和Cubit的API也是类似。Blocs不是在Bloc上调用函数然后直接发出一个新的状态,而是通过接收事件并且将传入的事件转化为状态输出

Flutter学习 - Bloc - 04 Bloc的使用


abstract class CounterExampleEvent{}

class AddEvent extends CounterExampleEvent {

}
class ReduceEvent extends CounterExampleEvent {

}

class CounterExampleBloc extends Bloc<CounterExampleEvent, int> {
  CounterExampleBloc() : super(0) 
  }

2. 状态改变

我们实现逻辑,通过我们的Event驱动

class CounterExampleBloc extends Bloc<CounterExampleEvent, int> {
  CounterExampleBloc() : super(0) {
    on<AddEvent>((event, emit) {
      emit(state+1);
    });
    on<ReduceEvent>((event, emit) {
      // TODO: implement event handler
      state-1;
      emit(state-1);
    });

  }
}

Bloc 要求我们通过 on<Event> 上注册事件处理程序 API, 而不是在 Cubit 中的功能. 事件处理程序负责将任何传入事件转换为零或多个传出状态.更新 EventHandler 来处理 AddEvent 事件. 事件我们可以通过 state getter 方法访问 bloc 的当前状态和通过 emit(state + 1) 改变状态.

3. 使用

我们使用BlocProvider进行初始化


class CounterExamplePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (BuildContext context) => CounterExampleBloc(),
      child: Builder(builder: (context) => _buildPage(context)),
    );
  }
  }

通过获取bloc 后对事件行为进行传入事件, bloc.add(AddEvent()),由于 Bloc 类继承了 BlocBase,因此我们可以随时通过 state getter 来访问 bloc 的当前状态,就像使用 Cubit 一样。

Widget _buildPage(BuildContext context) {
  final bloc = BlocProvider.of<CounterExampleBloc>(context);

  return Scaffold(
    appBar: AppBar(title: const Text('Bloc-Blocw范例')),
    body: Center(
      child: BlocBuilder<CounterExampleBloc, int>(
        builder: (context, state) {
          return Text(
            '点击了 ${bloc.state} 次',
            style: const TextStyle(fontSize: 30.0),
          );
        },
      ),
    ),
    floatingActionButton: FloatingActionButton(
      onPressed: () => bloc.add(AddEvent()),
      child: const Icon(Icons.add),
    ),
  );
}

4. Stream使用

就像 Cubit 一样,Bloc 是 Stream 的一种特殊类型,这意味着我们还可以订阅 Bloc 来实时更新其状态:

Widget _buildPage(BuildContext context) {
  final bloc = BlocProvider.of<CounterExampleBloc>(context);
  int count = 0;
  bloc.stream.listen((event) { count = event*2;});
  return Scaffold(
    appBar: AppBar(title: const Text('Bloc-Counter范例')),
    body: Center(
      child: BlocBuilder<CounterExampleBloc, int>(
        builder: (context, state) {
          return Text(
            '点击了 $count 次',
            style: const TextStyle(fontSize: 30.0),
          );
        },
      ),
    ),
    }

我们通过监听可以处理我们 自定义数据,当我们不想再接收更新时,在订阅上调用 cancel ,并关闭 Bloc

5. 观察

由于所有 Bloc 都扩展了 BlocBase,因此我们可以使用 onChange 观察 Bloc 的所有状态变化。

@override
void onChange(Change<int> change) {
  super.onChange(change);
  print(change);
}

Flutter学习 - Bloc - 04 Bloc的使用

  • onTransition

Bloc 和 Cubit 之间的主要区别因素是,由于 Bloc 是事件驱动的,因此我们也能够捕获有关触发状态更改的信息。

我们可以通过重写 onTransition 来做到这一点。


@override
void onTransition(Transition<CounterExampleEvent, int> transition) {
  super.onTransition(transition);
  print(transition);
}

Flutter学习 - Bloc - 04 Bloc的使用 onTransition 在 onChange 之前被调用,并且包含触发从 currentState 到 nextState 改变的事件。

6. 观察者

我们可以在自定义 BlocObserver 中重写 onTransition,以观察从一个位置发生的所有过渡。

class TestBlocObserver extends BlocObserver{

  @override
  void onChange(BlocBase bloc, Change change) {
    super.onChange(bloc, change);
    print('${bloc.runtimeType} $change');
  }

  @override
  void onTransition(Bloc bloc, Transition transition) {
    super.onTransition(bloc, transition);
    print('${bloc.runtimeType} $transition');
  }

  @override
  void onError(BlocBase bloc, Object error, StackTrace stackTrace) {
    print('${bloc.runtimeType} $error $stackTrace');
    super.onError(bloc, error, stackTrace);
  }

}

使用的时候和Cubit类似,CounterExampleBloc初始化之前添加观察者

Bloc.observer = TestBlocObserver();

打印结果

Flutter学习 - Bloc - 04 Bloc的使用

首先调用 onTransition(在全局之前先于本地),然后调用 onChange Bloc 实例的另一个独特功能是,它们使我们能够重写 onEvent,无论何时将新事件添加到 Bloc 都会调用 onEvent。就像 onChange 和 onTransition 一样,onEvent 可以在本地或全局重写。

@override
void onEvent(CounterExampleEvent event) {
  super.onEvent(event);
  print(event);
}

在BlocObserver类中

@override
void onEvent(Bloc bloc, Object? event) {
  super.onEvent(bloc, event);
  print('${bloc.runtimeType} $event');
}

打印结果: Flutter学习 - Bloc - 04 Bloc的使用

就会调用 onEvent。本地 onEvent 在 BlocObserver 中的全局 onEvent 之后被调用。

7. Cubit和Bloc

简单逻辑使用Cubit。

使用 Cubit 的最大优点之一就是简单。当创建一个 Cubit 时,我们只需要定义状态以及我们想要公开的改变状态的函数即可。相比之下,创建 Bloc 时,我们必须定义状态、事件和 EventHandler 实现。这使得 Cubit 更容易理解,并且涉及的代码更少。

对于一些复杂情况使用Bloc。

使用 Bloc 的最大优势之一就是知道状态变化的顺序以及触发这些变化的确切原因。对于对于应用程序功能至关重要的状态,使用更多事件驱动的方法来捕获状态变化之外的所有事件可能会非常有益。