flutter_bloc 使用解析

06/22/2022 08:54 上午 posted in  Flutter

flutter_bloc 使用将从下图的三个维度说明

初始化代码

来看下这三个生成的 bloc 文件:main_bloc,main_event,main_state

main_bloc:这里就是咱们主要写逻辑的页面了mapEventToState 方法只有一个参数,后面自动带了一个逗号,格式化代码就分三行了,建议删掉逗号,格式化代码。

class MainBloc extends Bloc<MainEvent, MainState> {
  MainBloc() : super(MainInitial());

  @override
  Stream<MainState> mapEventToState(
    MainEvent event,
  ) async* {
    // TODO: implement mapEventToState
  }
}

main_event:这里是执行的各类事件,有点类似 fish_redux 的 action 层

@immutable
abstract class MainEvent {}

main_state:状态数据放在这里保存,中转

@immutable
abstract class MainState {}

class MainInitial extends MainState {}

实现

主入口

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MainPage(),
    );
  }
}

说明

这里对于简单的页面,state 的使用抽象状态继承实现的方式,未免有点麻烦,这里我进行一点小改动,state 的实现类别有很多,官网写 demo 也有不用抽象类,直接 class,类似实体类的方式开搞的。

相关代码的注释写的比较多,大家可以着重看看

main_bloc
state 变量是框架内部定义的,会默认保存上一次同步的 MainSate 对象的值

class MainBloc extends Bloc<MainEvent, MainState> {
  MainBloc() : super(MainState(selectedIndex: 0, isExtended: false));

  @override
  Stream<MainState> mapEventToState(MainEvent event) async* {
    ///main_view中添加的事件,会在此处回调,此处处理完数据,将数据yield,BlocBuilder就会刷新组件
    if (event is SwitchTabEvent) {
      ///获取到event事件传递过来的值,咱们拿到这值塞进MainState中
      ///直接在state上改变内部的值,然后yield,只能触发一次BlocBuilder,它内部会比较上次MainState对象,如果相同,就不build
      yield MainState()
        ..selectedIndex = event.selectedIndex
        ..isExtended = state.isExtended;
    } else if (event is IsExtendEvent) {
      yield MainState()
        ..selectedIndex = state.selectedIndex
        ..isExtended = !state.isExtended;
    }
  }
}

全局 Bloc

说明

什么是全局 Bloc?

BlocProvider 介绍里面有这样的形容:BlocProvider should be used to create new blocs which will be made available to the rest of the subtree(BlocProvider 应该被用于创建新的 Bloc,这些 Bloc 将可用于其子树)

这样的话,我们只需要在主入口地方使用 BlocProvider 创建 Bloc,就能使用全局的 XxxBloc 了,这里的全局 XxxBloc,state 状态都会被保存的,除非关闭 app,否则 state 里面的数据都不会被还原!

注意:在主入口创建的 XxxBloc,在主入口处创建了一次,在其它页面均不需要再次创建,在任何页面只需要使用 BlocBuilder,便可以定点刷新及其获取全局 XxxBloc 的 state 数据

使用场景

全局的主题色,字体样式和大小等等全局配置更改;这种情况,在需要全局属性的地方,使用 BlocBuilder 对应的全局 XxxBloc 泛型去刷新数据就行了

跨页面去调用事件,既然是全局的 XxxBloc,这就说明,我们可以在任何页面,使用 BlocProvider.of(context)调用全局 XxxBloc 中事件,这就起到了一种跨页面调用事件的效果

使用全局 Bloc 做跨页面事件时,应该明白,当你关闭 Bloc 对应的页面,对应全局 Bloc 中的并不会被回收,下次进入页面,页面的数据还是上次退出页面修改的数据,这里应该使用 StatefulWidget,在 initState 生命周期处,初始化数据;或者在 dispose 生命周期处,还原数据源

思考下:全局 Bloc 对象存在周期是在整个 App 存活周期,必然不能创建过多的全局 Bloc,跨页面传递事件使用全局 Bloc 应当只能做折中方案