Flutter Application Bloc 侦听器未收到状态更新

时间:2021-02-05 18:04:17

标签: flutter dart bloc

我正在使用 flutter Bloc 将用户导航到登录页面或主屏幕,具体取决于他们是否经过身份验证。但是,在初始状态更改后,当我更改身份验证状态时,侦听器不会触发。

听众:

Widget build(BuildContext context) {
  return BlocListener<AuthenticationBloc, AuthenticationState>(
    listener: (context, state) {
      // Listener never gets called on statechange after the initial app startup

      // navigation based on authentication 
      }
    },
    child: SplashPage(),
  );
}

提供者在父小部件中初始化:

AuthenticationRepository authRepo = AuthenticationRepository();

Widget build(BuildContext context) {
  return MultiBlocProvider(
    providers: [
      BlocProvider<AuthenticationBloc>(
        create: (BuildContext context) =>
            AuthenticationBloc(authenticationRepository: authRepo),
      ),
      /*
         Other Providers
      */
    ],
    child: MaterialApp(
      title: 'myApp',
      home: StartUpPage(),
    ),
  );

当用户登录 mapEventState 在 AuthenticationBloc 中被调用时:

class AuthenticationBloc
    extends Bloc<AuthenticationEvent, AuthenticationState> {
  AuthenticationBloc({
    @required AuthenticationRepository authenticationRepository,
  })  : assert(authenticationRepository != null),
        _authenticationRepository = authenticationRepository,
        super(const AuthenticationState.unknown()) {
    _userSubscription = _authenticationRepository.userStream.listen(
      (user) => add(AuthenticationUserChanged(user)),
    );
  }

  final AuthenticationRepository _authenticationRepository;
  StreamSubscription<User> _userSubscription;

  @override
  Stream<AuthenticationState> mapEventToState(
    AuthenticationEvent event,
  ) async* {
    if (event is AuthenticationUserChanged) {
      yield _mapAuthenticationUserChangedToState(event);
    } else if (event is AuthenticationLogoutRequested) {
      unawaited(_authenticationRepository.logOut());
    }
  }

  @override
  Future<void> close() {
    _userSubscription?.cancel();
    return super.close();
  }

  AuthenticationState _mapAuthenticationUserChangedToState(
    AuthenticationUserChanged event,
  ) =>
      event.user != User.empty
          ? AuthenticationState.authenticated(event.user)
          : const AuthenticationState.unauthenticated();
}

我希望在用户登录和 AuthenticationState 更改时触发侦听器。如果有人知道我做错了什么,或者我遗漏了什么,我很乐意听到。

已于 2021 年 8 月 2 日编辑:

我使用一个简单的按钮再次检查了登录后状态是否发生变化。有了这个,我可以确认状态确实发生了变化并保存了正确的用户数据和身份验证状态。我确认的另一件事是使用 BlocBuilder IS 的 BlocBuilder 在用户登录时正确更新。

编辑 10-02-2021:

整个身份验证状态:

enum AuthenticationStatus { authenticated, unauthenticated, unknown }

class AuthenticationState extends Equatable {
  const AuthenticationState._({
    this.status = AuthenticationStatus.unknown,
    this.user = User.empty,
  });

  const AuthenticationState.unknown() : this._();

  const AuthenticationState.authenticated(User user)
      : this._(status: AuthenticationStatus.authenticated, user: user);

  const AuthenticationState.unauthenticated()
      : this._(status: AuthenticationStatus.unauthenticated, user: User.empty);

  final AuthenticationStatus status;
  final User user;

  @override
  List<Object> get props => [status, user];
}

编辑 12-02-2021:

删除不相关的代码

编辑 15-02-2021:

添加了整个身份验证 BloC

3 个答案:

答案 0 :(得分:1)

你能列出你的整个小部件树吗?

我想知道您的第一个小部件(包含侦听器的小部件)是否实际上没有被渲染(比如说,因为您在树中的某处有一个 if/else,这意味着它实际上并没有在事件发生时显示被解雇了)。

您可以使用 Flutter 检查器进行检查。否则,它是否运行在同一个 BuildContext 中?

如果您显示整个小部件树,这将更容易诊断。

答案 1 :(得分:0)

没有看到 BLoC 很难判断,但是您是否有可能在发出状态后创建侦听器。请记住,侦听器不会触发最后一个状态,只会触发侦听器创建后的状态。

请分享 BLoC 代码。

答案 2 :(得分:0)

看起来您的 AuthenticationRepository 通过侦听 _authenticationRepository.userStream 来调度 AuthenticationEvent。我认为问题在于您在 AuthenticationBloc 之前创建了 AuthenticationRepository 的实例,这可能会导致 AuthenticationStatus 在 BLoC 策略监听它之前发生变化.

不过如果您能提供 AuthenticationRepository 代码会更好。