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

Flutter Application Bloc listener not receiving state updates

我正在使用 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(),
    ),
  );

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

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 更改时触发。如果有人知道我做错了什么或者我遗漏了什么,我很乐意听到。

编辑 08-02-2021:

我再次检查了使用简单按钮登录后状态是否发生变化。有了这个,我可以确认状态确实发生了变化并保持了正确的用户数据和身份验证状态。我确认的另一件事是使用 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 的情况下很难判断,但您是否有可能在发出状态后创建侦听器。请记住,Listener 不会触发最后一个状态,只有在创建监听器后才会发出状态。

请分享 BLoC 代码。

您的 AuthenticationRepository 似乎通过监听 _authenticationRepository.userStream[=21= 来调度 AuthenticationEvent ].我认为问题在于您创建 AuthenticationRepository 的实例早于 AuthenticationBloc,这可能会导致 AuthenticationStatus 在 BLoC strats 收听它之前更改。

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

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

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

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

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