Flutter 入门与实战(八十九):使用BlocListener处理状态变化

2,809 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

前言

在 flutter_bloc提供了一个状态监听组件 BlocListener,当状态发生改变时会调用listener参数给定的回调函数,这个方法没有返回值,可以用于我们处理一些提醒,例如显示弹窗提醒或确认,显示状态信息等等。有了 BlocListener,相当于给我们提供了一个额外处理对象变化的入口。接下来我们通过BlocListener实现某些 App退出登录前的二次确认。

登录状态

为了简化逻辑,我们的登录数据只有一个枚举 LoginStatus,有三个状态:

  • logon:已登录
  • logout:已退出登录
  • logoutConfirm:退出登录确认

enum LoginStatus { logon, logout, logoutConfirm }

class LoginCubit extends Cubit<LoginStatus> {
  LoginCubit({initial = LoginStatus.logout}) : super(initial);

  void login() => emit(LoginStatus.logon);
  void logout() => emit(LoginStatus.logout);
  void logoutConfirm() => emit(LoginStatus.logoutConfirm);
}

业务逻辑

我们在屏幕中央放置一个按钮,根据登录状态切换按钮文本:

  • 已登录:显示为退出登录;
  • 已退出登录:显示为登录。

点击退出登录按钮的时候,弹出二次确认对话框,确认后更改状态为已退出登录,否则保持登录状态不变,对话框如下图所示。 image.png

代码实现

由于我们按钮和 BlocListener 都需要使用状态数据,因此使用 BlocProvider 放置在上层为 BlocListenerBlocBuilder 同时提供状态数据。

class BlocListenerWrapper extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (_) => LoginCubit(),
      child: BlocListenerDemo(),
    );
  }
}

BlocListener 部分的代码如下:

class BlocListenerDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('BlocListener 示例'),
      ),
      body: Center(
        child: BlocListener<LoginCubit, LoginStatus>(
          listener: (context, loginSatus) async {
            if (loginSatus == LoginStatus.logout ||
                loginSatus == LoginStatus.logon) {
              ScaffoldMessenger.of(context)
                ..hideCurrentSnackBar()
                ..showSnackBar(SnackBar(
                  content:
                      Text(loginSatus == LoginStatus.logout ? '已退出登录' : '登录成功'),
                  duration: Duration(seconds: 1),
                ));
            } else {
              var confirmed = await _confirmLogout(context);
              if (confirmed == true) {
                context.read<LoginCubit>().logout();
              }
            }
          },
          child: BlocBuilder<LoginCubit, LoginStatus>(
            builder: (context, loginSatus) => TextButton(
              child: Text(
                loginSatus == LoginStatus.logon ? '退出登录' : '登录',
                style: TextStyle(
                  fontSize: 24.0,
                ),
              ),
              onPressed: () {
                if (loginSatus == LoginStatus.logon) {
                  context.read<LoginCubit>().logoutConfirm();
                } else {
                  context.read<LoginCubit>().login();
                }
              },
            ),
          ),
        ),
      ),
    );
  }

当状态是已登录和已退出登录时显示一个 SnackBar 提示结果,而如果是确认登录,则弹出一个对话框。对话框会返回 truefalse,如果是 true 则表示确认退出,此时再调用 LoginCubitlogout 退出登录。源码已提交至:BLoC状态管理源码,运行效果如下:

屏幕录制2021-09-30 下午9.47.52.gif

总结

可以看到,有了BlocListener,我们可以实现类似后置拦截器的效果,在状态改变后做一些额外的的处理,比如提示信息,或者是做数据的上传、离线存储等。通过这种方式处理,可以降低业务代码的耦合度。

我是岛上码农,微信公众号同名,这是Flutter 入门与实战的专栏文章,提供体系化的 Flutter 学习文章。对应源码请看这里:Flutter 入门与实战专栏源码。如有问题可以加本人微信交流,微信号:island-coder

👍🏻:觉得有收获请点个赞鼓励一下!

🌟:收藏文章,方便回看哦!

💬:评论交流,互相进步!