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

Posted

技术标签:

【中文标题】Flutter Application Bloc 侦听器未接收到状态更新【英文标题】:Flutter Application Bloc listener not receiving state updates 【发布时间】:2021-05-10 02:16:48 【问题描述】:

我正在使用 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 日编辑:

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

2021 年 10 月 2 日编辑:

整个身份验证状态:

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];

2021 年 12 月 2 日编辑:

删除了不相关的代码

2021 年 2 月 15 日编辑:

添加了整个身份验证块

【问题讨论】:

当您尝试更改状态时会发生什么?你确定状态真的在改变吗? @Abion47 当用户在登录后被推送到用户流上时,AuthenticationUserChanged 事件被添加到身份验证 Bloc > mapEventToState > _mapAuthenticationUserChangedToState(event) > AuthenticationState.(un)authenticated 被调用 >创建一个新的身份验证状态,然后从 mapEventToState 产生。我检查了这些状态是否不同。 你能提供AuthenticationState代码吗? @NabeelParkar 代码已添加。启动时,状态从未知变为未经身份验证,用户为空。这会被侦听器捕获,后续更改不会。 你能列出你的整个小部件树吗?我想知道您的第一个小部件(包含侦听器的小部件)是否实际上没有被渲染(例如,因为您在树中的某处有一个 if/else,这意味着它在事件被触发时实际上并未显示。你可以用 Flutter 检查器检查。否则,它是否在同一个 BuildContext 中运行?如果你显示整个小部件树,这将更容易诊断。 【参考方案1】:

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

请分享 BLoC 代码。

【讨论】:

已添加。正如我之前提到的,状态第一次从未知变为未经身份验证时,它确实会捕获更改并路由到登录页面。如果您随后登录并且状态更改为已验证,则不会发生任何事情。 你能显示类用户吗?您可以尝试从状态中删除 Equatable 以确保您没有生成相同的状态(侦听器不会以相同的状态触发两次)。【参考方案2】:

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

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

【讨论】:

【参考方案3】:

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

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

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

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

【讨论】:

以上是关于Flutter Application Bloc 侦听器未接收到状态更新的主要内容,如果未能解决你的问题,请参考以下文章

不在yaml文件flutter中安装包bloc或flutter bloc

Flutter:BLoC 包 - bloc 提供者

Flutter Bloc - Flutter Bloc 状态未更新

Flutter 从其他 Bloc 监听 Bloc 状态

使用 flutter_bloc 库有啥缺点

Flutter BloC 模式:基于另一个 BloC 的流更新 BloC 流